我在C#中有两个相似的结构,每个结构都包含一个整数,但后者实现了get / set访问器。
为什么在分配Y
字段之前,我必须使用new
运算符初始化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;
}
}
答案 0 :(得分: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
}
}
不允许的原因是属性设置器可以观察到对象的未初始化状态。调用者不知道属性设置器是仅设置字段,还是更多。
答案 1 :(得分:7)
在第一种情况下,您只需指定字段。它不涉及结构的实际使用,只是将值设置到内存中(结构地址+堆栈上的字段偏移量)。
在第二种情况下,您调用方法set_a(int value)
,但因为变量未初始化而失败。
在第三种情况下,构造函数会为您初始化它,因此使用变量是正确的。
更新:这是规范!
“12.3确定分配”(ecma-334第122页)。
如果结构类型变量的每个实例变量都被认为是明确赋值的,那么它被认为是明确赋值的
答案 2 :(得分:5)
C# specification section 5.3 dealing with "Definite Assignment":
中介绍了这一点如果 struct-type 变量的每个实例变量都被认为是明确赋值的,那么它被认为是明确赋值的。
和
如果通往该位置的所有可能执行路径至少包含以下其中一项,则认为在指定位置明确分配了最初未分配的变量(第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;
}
您可以在LINQPad中进行测试。
请注意,如果您在其上调用代码,则编译器无法证明struct-type变量被认为是明确赋值的,而这正是您对属性所做的事情。因此,在可以在struct-type变量上使用属性之前,必须明确赋值。
答案 3 :(得分:-1)
值类型的new
运算符运行指定的构造函数。与引用类型不同,这是可选的,因此如果不使用new
,则隐式运行默认构造函数(您无法指定自己的默认构造函数,因此它始终具有为默认值提供默认值的效果。他们的类型的字段。)
至于编译错误的原因,我不太确定。有趣的是,在C#Interactive窗口中,
public struct Y
{
public int a { get; set; }
}
Y test;
test.a = 5;
工作得很好。