为什么不显式初始化readonly autoimplemented属性在c#6中有效?
更新1为什么不显式初始化readonly autoimplemented属性在c#6中有效?,c#,language-design,c#-6.0,C#,Language Design,C# 6.0,更新1 看来不是我的英语糟透了,就是人们对我的英语不感兴趣。。。了解我的问题,或者简单地看一下文章的标题 明确指出: 由于备份字段不可访问,因此可以对其进行读写 仅通过属性访问器,即使在包含类型内也是如此。 这意味着自动实现的只读或只读 属性没有意义,不允许使用 publicsstringmyproperty{get;}毫无意义,但编译器发出getter并不需要花费任何代价,甚至不用担心缺少setter。备份字段将用默认值初始化。这是什么意思?这意味着设计师花费了一些努力来实现验证,引入了可以忽
看来不是我的英语糟透了,就是人们对我的英语不感兴趣。。。了解我的问题,或者简单地看一下文章的标题 明确指出:
由于备份字段不可访问,因此可以对其进行读写 仅通过属性访问器,即使在包含类型内也是如此。 这意味着自动实现的只读或只读 属性没有意义,不允许使用
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变化的假设
- 或者解释编译器设计者如何以及为什么改变主意 关于什么有意义,什么没有意义
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 implementedreadonly
属性在我看来,没有显式初始化就留下来似乎有点奇怪。这可能是一个错误,而不是意图。我个人希望编译器在这种情况下需要显式初始化:
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,你就可以节省输入”,当人们真正想做的是拥有不变的属性时,这将他们推向了错误的方向。也就是说,“让我们防止无用的”是一个不错的主意,他们可能认为他们可以免费得到,但结果却变了