有区别吗?
class example
{
int i = 5;
}
class example2
{
int i;
public example2()
{
i = 5;
}
}
我更喜欢第二个,因为我不喜欢在声明变量后给出值。但技术上有区别吗?
答案 0 :(得分:4)
<击>是。如果某人派生自您的类example2
并忘记调用基类构造函数,则会跳过初始化,这可能是错误的。 击>
如果没有对构造函数参数的依赖,我倾向于在声明点(如第一个例子中)初始化。
答案 1 :(得分:4)
简答:否
长答案:
如果查看生成的IL code
,在example
类初始化完成的情况下,在调用构造函数之前,如example2
类中的类初始化在构造函数中完成。
example
上课
.class private auto ansi beforefieldinit example
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldc.i4.5
L_0002: stfld int32 ConsoleApplication1.example::i
L_0007: ldarg.0
L_0008: call instance void [mscorlib]System.Object::.ctor()
L_000d: ret
}
.field private int32 i
}
和example2
Class
.class private auto ansi beforefieldinit example2
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: call instance void [mscorlib]System.Object::.ctor()
L_0006: ldarg.0
L_0007: ldc.i4.5
L_0008: stfld int32 ConsoleApplication1.example2::i
L_000d: ret
}
.field private int32 i
}
答案 2 :(得分:2)
我应该说,有些情况可能存在差异(虽然代码很简单,就像问题中发布的那样,当然没有任何区别)。
请考虑以下代码:
public class Class1
{
public Class1()
{
Foo();
}
public virtual void Foo()
{
}
}
public class Class2 : Class1
{
protected int i = 5;
protected int j;
public Class2()
{
j = 5;
}
public override void Foo()
{
Console.WriteLine("i:" + i);
Console.WriteLine("j:" + j);
}
}
并测试它
new Class2().Foo();
输出将是:
i:5
j:0
i:5
j:5
线索是初始化器(当你在字段声明中赋值时)在基类构造函数之前运行。因此,从Foo
构造函数Class1
调用j
时,其默认值为0
。但是,当我们在完全创建的变量Foo
上调用new Class2().Foo();
时(Class2
构造函数完成时),j
已经有值5
。
虽然这是一个危险的设计 - 但是要在基类构造函数中调用virtual
方法,但是它并没有被禁止,应该知道这一点。
以下是J.Richter CLR通过C#提取的摘录:
编译器之前使用方便的语法初始化任何字段 调用基类的构造函数来保持这种印象 这些字段始终具有值作为源代码外观 使然。当基类的构造函数发生时,可能会出现问题 调用一个虚方法,该方法回调到由该方法定义的方法 派生类。如果发生这种情况,使用的字段初始化字段 在虚方法之前已经初始化了方便的语法 调用。