我一直想知道这一点。在C#中,何时设置具有默认值的实例变量 - 在构造函数之前或之后?
对于此代码:
public class Foo
{
public int bar=1;
public Foo()
{
bar = 2;
}
}
...
Console.WriteLine(new Foo().bar);
输出1还是2?
答案 0 :(得分:4)
构造期间的实例将首先遍历所有声明,然后进入构造函数本身。
因此,bar = 1将在bar = 2之前执行,但最终结果仍为bar = 2。
答案 1 :(得分:1)
它将返回2,您在构造函数修改后访问该属性。
答案 2 :(得分:1)
成员实例化首先在构造函数中添加。如果你查看使用Reflector实际创建的IL代码,这就是编译器用它做的事情:
.class auto ansi nested public beforefieldinit Foo
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldc.i4.1
L_0002: stfld int32 Test.Program/Foo::bar
L_0007: ldarg.0
L_0008: call instance void [mscorlib]System.Object::.ctor()
L_000d: nop
L_000e: nop
L_000f: ldarg.0
L_0010: ldc.i4.2
L_0011: stfld int32 Test.Program/Foo::bar
L_0016: nop
L_0017: ret
}
.field public int32 bar
}
因此,成员实例化首先放在构造函数中,然后调用基类型的构造函数,然后是你在构造函数中放入的代码。
答案 3 :(得分:1)
在规范的第10.11.3节中描述并证明了这种行为。
另见我关于这个主题的文章:
答案 4 :(得分:0)
你为什么不测试这个?
实例化类对象时,实质上是创建类的实例,然后运行构造函数。因此,它应输出2
答案 5 :(得分:0)
在调用构造函数之前,底层字节码没有任何特殊的能力来初始化这些值。 C#编译器负责排序,它在类型为.ctor
的方法中以字节码形式发出:
如果构造函数没有将this(...)
指定为链式构造函数,意味着它指定base(...)
或者根本不指定任何内容,那么它就是:
如果构造函数将this(...)
指定为链式构造函数,则顺序略有不同,因为链式构造函数将处理字段的初始化。
: this(...)
明确指出的构造函数。答案 6 :(得分:0)
如果没有发生这种情况,可能会造成一些非常令人困惑和不直观的情况。就像构造函数中的某些东西以某种特定的方式取决于bar的初始值一样,它不知道它是否已被初始化(或者更糟糕的是,bar是用户定义的类而不是int。是否为null因为构造函数该课程希望它是什么?还是只是没有被初始化?) 它有助于将构造函数视为你阶级的诞生过程,就像婴儿实际上从它的木乃伊中弹出一样,并初始化为子宫中的成长。 初始化等前提条件是给定的 - 你不会看到一个没有武器出生的婴儿,然后突然他们出现一小时后你会吗?