最初设置的类声明,内部与在构造函数中设置它们相同吗?

时间:2012-07-31 05:38:58

标签: c#

最初设置的类声明,内部与在构造函数中设置它们相同吗?

示例:

class test
{
     int test1 = 5;
}

它和

之间有什么区别吗?
class test
{
     int test1;
     public test()
     {
         test1 = 5;
     }
}  

如果没有差异,哪个更正确?

5 个答案:

答案 0 :(得分:3)

在具体情况下,您给出的没有功能差异。但是,当涉及继承时,字段初始化器可以以令人惊讶的方式运行。字段初始值设定项实际上是在构造函数之前调用的,并且当构造函数从最小派生到最大派生调用时,字段初始值设定项从最大派生到最少派生调用。因此,如果类A派生自B.当创建A的实例时,执行以下序列:A的字段初始值设定项,B的字段初始值设定项,System.Object构造函数,B的构造函数,A的构造函数。

以上仅适用于实例字段初始值设定项/构造函数。对于静态字段初始化器/构造函数,行为完全不同。

至于哪种情况在你的情况下是正确的,没有商定的约定,但读者通常会赞同一致性。

答案 1 :(得分:2)

对于大多数用途,您可以考虑两种成员初始化函数在功能上等效。

但是,您应该记住,在任何构造函数执行之前,成员声明中的赋值都会执行。正如Jon Skeet在评论中指出的那样,如果从基础构造函数调用虚方法,这种时序差异可能会产生可观察的工件。

“正确性”是一个意见问题。对于简单的整数值,初始值赋值似乎无关紧要,但是当您进入更复杂的类型(如日期或其他全对象)时,杂波因子开始上升。

对于我自己,我通常更喜欢将初始化作为构造函数体中的显式赋值语句执行,而不是在声明中遍布整个类。

答案 2 :(得分:1)

在查看IL代码差异时,您可以看到在案例1中,在调用构造函数之前分配了变量test,而在案例2中,在调用构造函数之后分配了它。

案例1

.class public auto ansi beforefieldinit WebApplication1.Class1
    extends [mscorlib]System.Object
{
    // Fields
    .field public int32 test1

    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x28d3
        // Code size 15 (0xf)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldc.i4.5
        IL_0002: stfld int32 WebApplication1.Class1::test1 <- HERE
        IL_0007: ldarg.0
        IL_0008: call instance void [mscorlib]System.Object::.ctor()  <- HERE
        IL_000d: nop
        IL_000e: ret
    } // end of method Class1::.ctor

} // end of class WebApplication1.Class1

案例2

.class public auto ansi beforefieldinit WebApplication1.Class2
    extends [mscorlib]System.Object
{
    // Fields
    .field public int32 test1

    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x28e3
        // Code size 17 (0x11)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor() <- HERE
        IL_0006: nop
        IL_0007: nop
        IL_0008: ldarg.0
        IL_0009: ldc.i4.5
        IL_000a: stfld int32 WebApplication1.Class2::test1 <- HERE
        IL_000f: nop
        IL_0010: ret
    } // end of method Class2::.ctor

} // end of class WebApplication1.Class2

答案 3 :(得分:0)

在你的情况下它是同一件事。但是如果有参数化构造函数和test1是从构造函数传递的值中分配的。

class test
{
    int test1;
    public test()
    {
        test1 = 5;
    }

    public test(int ctest)
    {
        test1 = ctest;
    }
}

If there is no difference, which is more correct to do?

开发者可以选择他想要的那个。

答案 4 :(得分:0)

这个名为Instance field initialization

class Test
{
     int test1 = 5;
}

它是如何运作的?

  

类的实例字段变量初始值设定项对应于在进入该类的任何一个实例构造函数(第10.10.1节)后立即执行的赋值序列。变量初始值设定项以它们出现在类声明中的文本顺序执行。

因此,在您的情况下,这两个字段初始化变体在功能上是相同的。

另外,我建议您看一下这个问题:C# member variable initialization; best practice?