3

有区别吗?

class example
{
    int i = 5;
}

class example2
{
    int i;

    public example2()
    {
        i = 5;
    }
}

我更喜欢第二个,因为我不喜欢在声明变量后给出值。但是技术上有区别吗?

4

3 回答 3

4

是的。如果有人从您的类派生example2并忘记调用基类构造函数,则跳过初始化,这可能很糟糕。

如果不依赖于构造函数参数,我倾向于在声明点进行初始化(如您的第一个示例)。

于 2013-02-14T02:20:30.303 回答
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 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

}
于 2013-02-14T02:20:50.507 回答
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

线索是初始化程序(当您在字段声明中分配值时)在基类构造函数之前运行。因此,当FooClass1构造函数调用时j具有其默认值,即0. 但是当我们调用Foo一个完全创建的变量new Class2().Foo();时(当Class2构造函数完成时),j已经有了 value 5

尽管这是一种危险的设计——virtual在基类构造函数中调用方法,但是,它并没有被禁止,人们应该意识到这一点。

以下是通过 C# 摘录的 J.Richter CLR:

编译器在调用基类的构造函数之前使用方便的语法初始化任何字段,以保持这些字段始终具有源代码外观所指示的值的印象。当基类的构造函数调用一个虚方法,该方法回调到派生类定义的方法时,就会出现潜在的问题。如果发生这种情况,使用方便语法初始化的字段在调用虚拟方法之前已经初始化。

于 2013-02-14T02:28:54.263 回答