繁体   English   中英

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

[英]C# - What's the difference between these two ways of instancing a class property?

基本的C#问题在这里。

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

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

VS

public class MyClass
{
    public MyObject;

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

调用基本构造函数之前初始化具有初始化程序的字段,而如果初始化程序在主体中,则仅在调用基本构造函数之后执行。

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

示例代码:

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
    }
}

我编译这些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类)的调用顺序。 test.MyObject test.MyClass2 :: MyObject)

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

  • MyObject初始化程序
  • 类初始值设定项(构造函数赋值)
  • 基类初始值设定项(基类构造函数)

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

  • 基类初始值设定项(基类构造函数)
  • MyObject初始化程序
  • 类初始值设定项(构造函数赋值)

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

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();
    }
}

重要的是要注意(在C#中)对字段的初始化程序赋值将在调用任何基类构造函数之前发生(在这个问题中可以证明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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM