为什么不显式初始化readonly autoimplemented属性在c#6中有效?

为什么不显式初始化readonly autoimplemented属性在c#6中有效?,c#,language-design,c#-6.0,C#,Language Design,C# 6.0,更新1 看来不是我的英语糟透了,就是人们对我的英语不感兴趣。。。了解我的问题,或者简单地看一下文章的标题 明确指出: 由于备份字段不可访问,因此可以对其进行读写 仅通过属性访问器,即使在包含类型内也是如此。 这意味着自动实现的只读或只读 属性没有意义,不允许使用 publicsstringmyproperty{get;}毫无意义,但编译器发出getter并不需要花费任何代价,甚至不用担心缺少setter。备份字段将用默认值初始化。这是什么意思?这意味着设计师花费了一些努力来实现验证,引入了可以忽

更新1
看来不是我的英语糟透了,就是人们对我的英语不感兴趣。。。了解我的问题,或者简单地看一下文章的标题

明确指出:

由于备份字段不可访问,因此可以对其进行读写 仅通过属性访问器,即使在包含类型内也是如此。 这意味着自动实现的只读或只读 属性没有意义,不允许使用

publicsstringmyproperty{get;}
毫无意义,但编译器发出getter并不需要花费任何代价,甚至不用担心缺少setter。备份字段将用默认值初始化。这是什么意思?这意味着设计师花费了一些努力来实现验证,引入了可以忽略的功能

现在我们考虑C<6:

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


public string FirstName { get; } = "Jane";
在后一种情况下,也可以在构造函数中设置属性:

public class Program
{
    public string ImagePath { get; }

    public static void Main()
    {    
    }

    public Program()
    {
        ImagePath = "";
    }      
}
但仅在声明属性的类的构造函数中。派生类无法设置属性的值

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

property string My {get;}
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";
    }
}
这100%等同于C#5违禁财产。它毫无意义。
但这种声明在C#5中无效,在C#6中生效。然而,语义根本没有改变:如果没有显式初始化,这个属性是无用的

这就是为什么我要问:

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

我希望看到的答案是:

  • 要么推翻我最初关于C#6变化的假设
  • 或者解释编译器设计者如何以及为什么改变主意 关于什么有意义,什么没有意义
我发现答案是完全不相关的。这只是事实。我寻找原因。我不相信编译器设计者决定改变编译器的行为仅仅是掷硬币

这是一个很好的答案

原始问题

在VS2015中,此代码编译时没有错误:

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中无效

Initializable auto implemented
readonly
属性在我看来,没有显式初始化就留下来似乎有点奇怪。这可能是一个错误,而不是意图。我个人希望编译器在这种情况下需要显式初始化:

publicstringimagepath{get;}=default(string)

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

property string My {get;}
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";
    }
}
但是,如果编译器可以检查局部变量是否未初始化,则属性也可以这样做


那么为什么是这样呢?

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

public string ImagePath { get; private set; }
假设您不打算在类之外设置该属性

至于为什么你必须声明一个setter或者手动实现这个属性——好吧,一个你可以从中读取的属性有什么好处,但是它总是返回它类型的默认值,因为没有办法设置它?相反,一个可以写入但既不能读取也不能钩住其setter的属性有什么好处


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

我不知道您的问题为什么被否决。这是一个有趣的观察结果,但请记住,这并不是一个突破性的变化——它只是“新功能”,是其他功能的“剩余”——自动实现属性的初始化

这意味着它以前没有意义,但现在有了意义

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

interface IPerson
{
    int Age { get; }
}

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

,问题不在于它为什么无效c#5,但是为什么它被设置为有效的C#6。除此之外,只有getter自动属性在C#6.0之前才被添加,因此C#5大喊大叫@hvd:因为在C#6中,您可以为只读属性选择值,这使得它实际上很有用。我添加了最后一段来明确提到这一点。@vonorinp:编译器不是为了让您知道您编写的内容是否无用,而是为了验证它在语言规范中是否合法。@voroninp a)您仍然可以在构造函数中赋值,因此“无用”还需要检查构造函数AST,b)IIRC设计师们认为,“如果你只接受一个私有setter,你就可以节省输入”,当人们真正想做的是拥有不变的属性时,这将他们推向了错误的方向。也就是说,“让我们防止无用的”是一个不错的主意,他们可能认为他们可以免费得到,但结果却变了