这两者有区别吗?

时间:2013-02-14 02:14:34

标签: c# .net

有区别吗?

class example
{
    int i = 5;
}

class example2
{
    int i;

    public example2()
    {
        i = 5;
    }
}

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

3 个答案:

答案 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#提取的摘录:

  

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