简体   繁体   English

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

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

Basic C# question here. 基本的C#问题在这里。

What is the difference between creating an instance of a class property / field either as you declare it or in the constructor of the object in question. 在声明它时或在相关对象的构造函数中创建类属性/字段的实例有什么区别。 For example: 例如:

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

vs VS

public class MyClass
{
    public MyObject;

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

A field with an initializer is initialized before the base constructor is called, whereas if the initializer is in the body, that only gets executed after the base constructor is called. 调用基本构造函数之前初始化具有初始化程序的字段,而如果初始化程序在主体中,则仅在调用基本构造函数之后执行。

This can be relevant if the base constructor calls a virtual method - but personally I'd try to avoid that situation. 如果基础构造函数调用虚方法,这可能是相关的 - 但我个人试图避免这种情况。

Sample code: 示例代码:

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

I compile these C# code: 我编译这些C#代码:

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

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

I got IL assembly: 我有IL装配:

MyClass1: 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: 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

It is prefectly clear that difference is only in the order of call to the base class constructor (System.Object::.ctor()), MyObject initializer (test.MyObject::.ctor()) and the class initializer (stfld class test.MyObject test.MyClass2::MyObject) 完全清楚的是差别仅在于对基类构造函数(System.Object ::。ctor()),MyObject初始化程序(test.MyObject ::。ctor())和类初始化程序(stfld类)的调用顺序。 test.MyObject test.MyClass2 :: MyObject)

In the first case, MyClass1 initializes as follows: 在第一种情况下,MyClass1初始化如下:

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

But, MyClass2 initializes by that order: 但是,MyClass2按该顺序初始化:

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

You can also use a static constructor that gets called before any other constructor where you can init static variables 您还可以使用在可以初始化静态变量的任何其他构造函数之前调用的静态构造函数

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

It's important to note that (in C#) the initializer assignment to the field will occur before the call to any base class constructor (as evidenced in this question about whether VB could be forced to do the same thing). 重要的是要注意(在C#中)对字段的初始化程序赋值将在调用任何基类构造函数之前发生(在这个问题中可以证明VB是否可以强制执行相同的操作)。

This means you can't use initializer syntax to reference a field of your base class (ie you can't directly translate this VB into C#): 这意味着您不能使用初始化程序语法来引用基类的字段(即您无法直接将此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