首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么不显式初始化只读自动实现属性在c# 6中是有效的?

为什么不显式初始化只读自动实现属性在c# 6中是有效的?
EN

Stack Overflow用户
提问于 2016-05-12 18:47:54
回答 2查看 186关注 0票数 0

更新1

似乎要么我的英语太糟糕了,要么人们就是不给……要理解我要问的是什么,或者简单地看一下帖子的标题。

C#5规范明确指出:

因为备份字段不可访问,因此只能通过属性访问器读取和写入它,甚至在包含的类型中也是如此。这意味着自动实现只读或只写属性没有意义的,并且是不允许的。

public string MyProperty {get;}没有任何意义,但是编译器不需要发布getter,甚至不用为缺乏setter而争论不休。支持字段将使用默认值初始化。什么意思?这意味着设计人员花费了一些来实现验证,引入可能被忽略的功能。

现在让我们考虑一下C#6:

在C#6中,自动实现的属性的初始化是介绍

代码语言:javascript
复制
public string FirstName { get; set; } = "Jane";

代码语言:javascript
复制
public string FirstName { get; } = "Jane";

在后一种情况下,还可以在构造函数中设置属性:

代码语言:javascript
复制
public class Program
{
    public string ImagePath { get; }

    public static void Main()
    {    
    }

    public Program()
    {
        ImagePath = "";
    }      
}

但仅在声明属性的类的构造函数中。派生类不能设置属性值。

现在,如果这个属性没有在构造函数中初始化,那么问自己这个属性意味着什么:

代码语言:javascript
复制
property string My {get;}

这是一项100%相当于C#5禁止的财产。它没有意义。

但是这种声明在C#5中是无效的,在C#6中是有效的,但是语义并没有改变:如果没有显式初始化,这个属性是无用的。

所以我才问:

为什么不显式初始化只读自动实现属性在c# 6中有效?

我希望看到的答案是:

  • 要么揭穿我最初对C#6变化的假设
  • 或者解释编译器设计人员如何以及为什么改变了他们对什么有意义和什么没有意义的想法。

我发现It's by design的答案完全无关紧要。这只是一个事实。我找理由。我不相信编译器设计者仅仅是抛硬币就决定编译器行为的改变。

这是一个好答案的示例

原始问题

VS2015中,编译该代码时没有出现错误:

代码语言:javascript
复制
public class Program
{
    public string ImagePath { get; }

    public static void Main()
    {
        Console.WriteLine("Hello World");
    }
}

然而,在VS2013中,我得到了错误:

编译错误(第5行,第28行):'Program.ImagePath.get‘必须声明一个主体,因为它没有标记为抽象或外部。自动实现的属性必须同时定义get和set访问器。

我知道可初始化的自动实现属性,如果VS2015字段获得默认值,即此处的null。但是有趣的是,为什么这个片段在C# 5中是无效的?

初始化自动实现的readonly属性没有显式初始化,在我看来有点奇怪。这很可能是一个错误,而不是意图。在这种情况下,我个人更希望编译器需要显式初始化:

public string ImagePath { get; } = default(string);

好的,我知道在构造函数中也可以分配这样的属性:

代码语言:javascript
复制
public class Program
{
    public string ImagePath { get; }

    public static void Main()
    {    
    }

    public Program()
    {
        ImagePath = "";
        DoIt();
    }

    public void DoIt()
    {
        //ImagePath = "do it";
    }       
}

public class My : Program 
{
    public My()
    {
        //ImagePath = "asdasd";
    }
}

但是,如果编译器可以检查局部变量没有初始化,则属性也可以这样做。

那为什么它是这样的呢?

EN

回答 2

Stack Overflow用户

发布于 2016-05-12 18:52:17

编译器告诉您,自动属性必须同时定义两个访问器。例如,您可以用

代码语言:javascript
复制
public string ImagePath { get; private set; }

假设您不打算在类之外设置该属性。

至于为什么您必须声明一个setter或者手动实现这个属性--那么,您可以读取的属性有什么用呢,但是它的类型总是返回默认值,因为没有方法来设置它?反过来说,您可以写入但既不能读取也不能链接到其设置器的属性有什么好处?

C# 6.0为您提供了拥有一次写一次、读取许多自动属性的选项;这是一个巨大的差异,因为值可以任意选择,允许您为具有不可变值的属性提供方便的语法。

票数 5
EN

Stack Overflow用户

发布于 2016-05-13 09:37:28

我不知道为什么你的问题被否决了。这是一个有趣的观察,但请记住,这不是一个突破性的变化-它只是‘新的功能’,是其他功能的‘剩余物’-初始化自动实现的属性。

这意味着它以前没有任何意义,但现在它已经意识到了。

此外,我认为这是有道理的。例如,当您有一些基类或接口时

代码语言:javascript
复制
interface IPerson
{
    int Age { get; }
}

总有一天,您可能希望在与年龄无关的情况下实现空对象模式。在c#5中,您必须编写public int Age { get { return 0; } },而在c#6中,您只需执行public int Age { get; },甚至可以将接口转换为抽象类,只需将其定义从interface更改为abstract class

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37195141

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档