簡體   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