有区别吗?
class example
{
int i = 5;
}
class example2
{
int i;
public example2()
{
i = 5;
}
}
我更喜欢第二个,因为我不喜欢在声明变量后给出值。但是技术上有区别吗?
是的。如果有人从您的类派生example2
并忘记调用基类构造函数,则跳过初始化,这可能很糟糕。
如果不依赖于构造函数参数,我倾向于在声明点进行初始化(如您的第一个示例)。
简短的回答:没有
长答案:
如果您查看生成的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 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
}
我应该说,在某些情况下可能存在差异(尽管如果代码很简单,就像问题中发布的那样,当然没有任何区别)。
考虑以下代码:
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
已经有了 value 5
。
尽管这是一种危险的设计——virtual
在基类构造函数中调用方法,但是,它并没有被禁止,人们应该意识到这一点。
以下是通过 C# 摘录的 J.Richter CLR:
编译器在调用基类的构造函数之前使用方便的语法初始化任何字段,以保持这些字段始终具有源代码外观所指示的值的印象。当基类的构造函数调用一个虚方法,该方法回调到派生类定义的方法时,就会出现潜在的问题。如果发生这种情况,使用方便语法初始化的字段在调用虚拟方法之前已经初始化。