自动属性和结构不要混合?
在回答这个post的时候 ,围绕着一些小的结构,我偶然发现了以下情况:
以下结构使用int字段是完全合法的:
struct MyStruct { public MyStruct ( int size ) { this.Size = size; // <-- Legal assignment. } public int Size; }
但是,使用自动属性的以下结构不能编译:
struct MyStruct { public MyStruct ( int size ) { this.Size = size; // <-- Compile-Time Error! } public int Size{get; set;} }
返回的错误是“这个对象不能在所有的字段被赋值之前使用”。 我知道这是一个结构的标准过程:任何属性的后台字段必须从结构的构造函数中直接分配(而不是通过属性的set访问器)。
解决scheme是使用明确的后台字段:
struct MyStruct { public MyStruct(int size) { _size = size; } private int _size; public int Size { get { return _size; } set { _size = value; } } }
(请注意,VB.NET不会有这个问题,因为在VB.NET中,所有字段在初次创build时都会自动初始化为0 / null / false。)
在C#中使用结构体的自动属性时,这似乎是一个不幸的限制。 从概念上思考,我想知道这是不是一个合理的地方,有一个exception,允许在一个结构的构造函数中调用属性设置访问器,至less对于自动属性?
这是一个小问题,几乎是一个边缘案例,但我想知道别人怎么看待这个…
从C#6开始:这不再是一个问题
成为C#6,你需要调用默认的构造函数来工作:
public MyStruct(int size) : this() { Size = size; }
这里一个更大的问题是你有一个可变的结构。 这绝不是一个好主意。 我会做到这一点:
public int Size { get; private set; }
技术上不是一成不变的,但足够接近。
使用最新版本的C#,您可以改进:
public int Size { get; }
现在只能在构造函数中赋值了。
你可以通过首先调用默认的构造函数来解决这个问题:
struct MyStruct { public MyStruct(int size) : this() { this.Size = size; // <-- now works } public int Size { get; set; } }
另一个模糊的解决方法是在Managed Extensibility Framework (通过KrzysztofKoźmic )的临时Tuple
类中find一个:
public struct TempTuple<TFirst, TSecond> { public TempTuple(TFirst first, TSecond second) { this = new TempTuple<TFirst, TSecond>(); // Kung fu! this.First = first; this.Second = second; } public TFirst First { get; private set; } public TSecond Second { get; private set; }
(来自Codeplex: Tuple.cs的完整源代码)
我也注意到CS0188的文档已经更新,增加:
如果您在尝试初始化struct构造函数中的某个属性时看到此错误,则解决方法是更改构造函数参数以指定backing字段而不是属性本身。 自动实现的属性应该避免在结构中,因为它们没有后台字段,因此不能以任何方式从构造函数初始化。
所以我认为官方的指导意见是当你遇到这个问题的时候,在你的结构中使用旧式的属性,这个问题可能比迄今为止探索的另外两种方法中的任何一个都不那么模糊(也更易读)。