[翻译]C# Object Initialization[完整版]

原文地址:

http://www.csharp411.com/c-object-initialization/

C#初始化类型的理解


当构造一个C#对象时,理解对象的作用域和构造器被初始化的序列是很重要的



  1. Derived static fields
  2. Derived static constructor
  3. Derived instance fields
  4. Base static fields
  5. Base static constructor
  6. Base instance fields
  7. Base instance constructor
  8. Derived instance constructor

示例

下面的是一个C#控制台程序的例子,这个例子演示了对象初始化的次序


这个程序创建基对象的派生对象,包含了静态化和实例化构造器以及作用域,两个作用域"Field1"和"Field2"在他们的定义里被初始化,然而 "Field3"在构造器里被初始化.同时也包含了一个证明为什么不能从构造器里调用虚方法的虚方法.当每个作用域和构造器被初始化时就会写入控制台,因 此你可以看到初始化的序列



using System;

namespace ObjectInit
{
    
class Program
    
{
        
static void Main( string[] args )
        
{
            Derived d 
= new Derived();
            Console.ReadLine();
        }

    }

    
class Base
    
{
        
public Base()
        
{
            Console.WriteLine( 
"Base.Instance.Constructor" );
            
this.m_Field3 = new Tracker( "Base.Instance.Field3″ );
            this.Virtual();
        }

        
static Base()
        
{
            Console.WriteLine( 
"Base.Static.Constructor" );
        }

        
private Tracker m_Field1 = new Tracker( "Base.Instance.Field1″ );
        private Tracker m_Field2 = new Tracker( "Base.Instance.Field2″ );
        private Tracker m_Field3;
        
static private Tracker s_Field1 = new Tracker( "Base.Static.Field1″ );
        static private Tracker s_Field2 = new Tracker( "Base.Static.Field2″ );
        virtual public void Virtual()
        
{
            Console.WriteLine( 
"Base.Instance.Virtual" );
        }

    }

    
class Derived : Base
    
{
        
public Derived()
        
{
            Console.WriteLine( 
"Derived.Instance.Constructor" );
            
this.m_Field3 = new Tracker( "Derived.Instance.Field3″ );
        }

        
static Derived()
        
{
            Console.WriteLine( 
"Derived.Static.Constructor" );
        }

        
private Tracker m_Field1 = new Tracker( "Derived.Instance.Field1″ );
        private Tracker m_Field2 = new Tracker( "Derived.Instance.Field2″ );
        private Tracker m_Field3;
        
static private Tracker s_Field1 = new Tracker( "Derived.Static.Field1″ );
        static private Tracker s_Field2 = new Tracker( "Derived.Static.Field2″ );
        override public void Virtual()
        
{
            Console.WriteLine( 
"Derived.Instance.Virtual" );
        }

    }

    
class Tracker
    
{
        
public Tracker( string text )
        
{
            Console.WriteLine( text );
        }

    }

}


下面就是来自这个示例程序的控制台输出


Derived.Static.Field1
Derived.Static.Field2
Derived.Static.Constructor
Derived.Instance.Field1
Derived.Instance.Field2
Base.Static.Field1
Base.Static.Field2
Base.Static.Constructor
Base.Instance.Field1
Base.Instance.Field2
Base.Instance.Constructor
Base.Instance.Field3
Derived.Instance.Virtual
Derived.Instance.Constructor
Derived.Instance.Field3
2个阶段的构建
       

注意在C#对象初始化的问题中还有个潜在的圈套。当初始化以派生对象开始转到基类对象时,构造函数以相反次序进行初始化,先执行基类构造函数,再执行派生函数。


        当你试图通过基构造函数调用一个虚方法时,上述情况就会发生。因为派生构造函数还未被执行,所以当虚方法通过基类函数执行时,派生对象或许就不会完全初始化。


        正如在案例程序显示的那样,当基构造函数调用虚方法时(程序输出显示:Derived.Instance.Virtual),由于派生构造函数未被执行, 派生对象的Field3并未被初始化。如果虚方法是建立在一个需要被初始化的Field3,此时程序将出错。


        因此,你不能在对象函数中使用虚方法。而是在你第一次构建对象处执行“2个阶段的构建”,此时再使用虚方法,如下:


       

Derived

d =

new Derived

();


        d.Virtual();



C#对象初始化提示:
      

一些关于C#对象初始化的一般规则和提示:


      

先变量后构造函数.

变量先被初始化,然后构造函数被执行


      

先静态化后实例化.

当一个类被访问时,静态变量和构造函数最先被初始化.接着是对象的实例化变量和构造函数被初始化


      

先派生类后基类.

对于变量和静态构造函数,派生对象在基对象之前被初始化.比如C类派生自B类,B类派生自A类,那么变量和静态构造函数被初始化次序是C-B-A.


      

除了实例构造函数.

对于实例构造函数,基类构造函数在派生类构造函数之前执行,实例构造函数被执行次序是A-B-C.


      

不要假定变量的次序.

Fields依据它们在源文件中的声明的顺序依次初始化.然而,自从程序员和工具可以随意安排变量的声明后,你不应该在依靠变量任何特别的次序初始化


      

对虚方法用两个阶段的构建.

避免从一个构造器调用虚方法. 如果在初始化一个对象时需要调用一些虚方法,应在完整构造该对象的地方使用两阶段的构建,并随后调用已构造对象的初始化方法。

Tags:  翻译 构造函数 初始化 OOM 对象

延伸阅读

最新评论

发表评论