1

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

例子:

class test
{
     int test1 = 5;
}

那和这有什么区别吗

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

如果没有区别,哪个更正确?

4

5 回答 5

3

在您给出的特定情况下,没有功能差异。但是,当涉及到继承时,字段初始值设定项可能会以令人惊讶的方式表现。字段初始值设定项实际上是在构造函数之前调用的,而构造函数的调用顺序是从最不派生到最派生的,而字段初始值设定项是从最派生到最不派生调用的。因此,如果类 A 派生自 B。当创建 A 的实例时,将执行以下顺序:A 的字段初始值设定项、B 的字段初始值设定项、System.Object 构造函数、B 的构造函数、A 的构造函数。

以上仅适用于实例字段初始化器/构造器。对于静态字段初始化器/构造器,行为是完全不同的。

至于在您的情况下哪个是正确的,没有约定俗成的约定,但读者通常会欣赏一致性。

于 2012-07-31T06:00:05.990 回答
2

对于大多数目的,您可以认为这两种成员初始化风格在功能上是等效的。

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

“正确性”是一个见仁见智的问题。对于简单的整数值,初始值分配似乎足够无害,但是当您进入更复杂的类型(如日期或其他完整对象)时,混乱因素开始上升。

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

于 2012-07-31T05:43:40.543 回答
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
于 2012-07-31T05:47:30.920 回答
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?

由开发人员选择他想要的。

于 2012-07-31T05:42:20.840 回答
0

这称为实例字段初始化

class Test
{
     int test1 = 5;
}

它是如何工作的?

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

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

另外,我想建议你看看这个问题:C# member variable initialization; 最佳实践?.

于 2012-07-31T05:46:39.513 回答