C# - 实现类属性的这两种方式有什么区别?

时间:2011-01-28 10:25:16

标签: c#

基本的C#问题在这里。

在声明它时或在相关对象的构造函数中创建类属性/字段的实例有什么区别。例如:

public class MyClass
{
    public MyObject = new MyObject();
}

VS

public class MyClass
{
    public MyObject;

    public MyCLass()
    {
        MyObject = new MyObject();
    }
}

4 个答案:

答案 0 :(得分:23)

在调用基础构造函数之前初始化具有初始化程序的字段,而如果初始化程序位于正文中,那么只有在基本构造函数被调用之后才会执行

如果基础构造函数调用虚方法,这可能是相关的 - 但我个人试图避免这种情况。

示例代码:

public class Base
{
    public Base()
    {
        Dump();
    }

    public virtual void Dump() {}
}

public class Child : Base
{
    private string x = "Initialized at declaration";
    private string y;

    public Child()
    {
        y = "Initialized in constructor";
    }

    public override void Dump()
    {
        Console.WriteLine(x); // Prints "Initialized at declaration"
        Console.WriteLine(y); // Prints "" as y is still null
    }
}

答案 1 :(得分:3)

我编译了这些C#代码:

public class MyClass1
{
    public MyObject MyObject = new MyObject();
}
public class MyClass2
{
    public MyObject MyObject;

    public MyClass2()
    {
        MyObject = new MyObject();
    }
}

我得到IL汇编:

MyClass1的:

.class public auto ansi beforefieldinit test.MyClass1
       extends [mscorlib]System.Object
{
  .field public class test.MyObject MyObject
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // code size:       19 (0x13)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  newobj     instance void test.MyObject::.ctor()
    IL_0006:  stfld      class test.MyObject test.MyClass1::MyObject
    IL_000b:  ldarg.0
    IL_000c:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0011:  nop
    IL_0012:  ret
  } // end of method MyClass1::.ctor

} // end of class test.MyClass1

MyClass2:

.class public auto ansi beforefieldinit test.MyClass2
       extends [mscorlib]System.Object
{
  .field public class test.MyObject MyObject
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // code size:       21 (0x15)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  nop
    IL_0008:  ldarg.0
    IL_0009:  newobj     instance void test.MyObject::.ctor()
    IL_000e:  stfld      class test.MyObject test.MyClass2::MyObject
    IL_0013:  nop
    IL_0014:  ret
  } // end of method MyClass2::.ctor
} // end of class test.MyClass2

完全清楚的是,区别仅在于对基类构造函数(System.Object ::。ctor()),MyObject初始化程序(test.MyObject ::。ctor())和类初始化程序的调用顺序。 (stfld class test.MyObject test.MyClass2 :: MyObject)

在第一种情况下,MyClass1初始化如下:

  • MyObject初始化程序
  • 类初始化器(构造函数分配)
  • 基类初始化器(基类构造函数)

但是,MyClass2按该顺序初始化:

  • 基类初始化器(基类构造函数)
  • MyObject初始化程序
  • 类初始化器(构造函数分配)

答案 2 :(得分:2)

您还可以使用在可以初始化静态变量的任何其他构造函数之前调用的静态构造函数

public class Bus
{
   private static object m_object= null;

    // Static constructor:
    static Bus()
    {
        m_object = new object();

        System.Console.WriteLine("The static constructor invoked.");
    }

    public static void Drive()
    {
        System.Console.WriteLine("The Drive method invoked.");
    }
}

class TestBus
{
    static void Main()
    {
        Bus.Drive();
    }
}

答案 3 :(得分:1)

重要的是要注意(在C#中)字段的初始化程序赋值将在调用任何基类构造函数之前发生(如this question中关于VB是否可以强制执行相同操作所证明的那样)。

这意味着您无法使用初始化程序语法来引用基类的字段(即,您无法直接将此VB转换为C#):

Public Class Base
    Protected I As Int32 = 4
End Class

Public Class Class2
    Inherits Base

    Public J As Int32 = I * 10
End Class