我在C#中有两个相似的结构,每个结构都包含一个整数,但后者有实现的get/set访问器.
为什么在分配字段之前必须Y
使用new
运算符初始化struct a
?是y
仍然当我初始化它的值类型new
?
public struct X
{
public int a;
}
public struct Y
{
public int a { get; set; }
}
class Program
{
static void Main(string[] args)
{
X x;
x.a = 1;
Y y;
y.a = 2; // << compile error "unused local variable" here
Y y2 = new Y();
y2.a = 3;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 14
一个有效而另一个有效的原因是你不能在未初始化的对象上调用方法.属性设置器也是方法.
public struct X
{
public int a;
public void setA(int value)
{ this.a = value; }
}
public struct Y
{
public int a { get; set; }
}
class Program
{
static void Main(string[] args)
{
X x;
x.setA(1); // A: error
x.a = 2; // B: okay
Y y;
y.a = 3; // C: equivalent to A
}
}
Run Code Online (Sandbox Code Playgroud)
不允许的原因是属性设置器可以观察对象的未初始化状态.调用者不知道属性设置器是仅设置字段,还是更多.
在第一种情况下,您只需指定字段.它不涉及结构的实际使用,只是将值设置到内存中(结构地址+堆栈上的字段偏移).
在第二种情况下,您调用方法set_a(int value)
,但因为变量未初始化而失败.
在第三种情况下,构造函数为您初始化它,因此使用变量是可以的.
更新:这是规格!
"12.3确定任务"(ecma-334第122页).
如果结构类型变量的每个实例变量都被认为是明确赋值的,则它被认为是明确赋值的
如果结构类型变量的每个实例变量都被认为是明确赋值的,则它被认为是明确赋值的.
和:
如果通往该位置的所有可能执行路径至少包含以下之一,则认为在给定位置明确分配了最初未分配的变量(第5.3.2节):
*一个简单的赋值(第7.13.1节),其中变量是左操作数.
*......
因此,这也有效:
void Main()
{
X x;
x.a = 1;
x.b = 2;
x.Dump();
}
public struct X
{
public int a;
public int b;
}
Run Code Online (Sandbox Code Playgroud)
您可以在LINQPad中测试它.
请注意,如果您在其上调用代码,则编译器无法证明struct-type变量被认为是明确赋值的,而这正是您对属性所做的事情.因此,在可以在struct-type变量上使用属性之前,必须明确赋值.