首页 > 编程开发 > Objective-C编程 >
-
c# Object initialization 完整版
原文地址:http://www.csharp411.com/c-object-initialization/
当构造一个C#对象时,理解对象的作用域和构造器被初始化的序列是很重要的
Derived static fields
Derived static constructor
Derived instance fields
Base static fields
Base static constructor
Base instance fields
Base instance constructor
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依据它们在源文件中的声明的顺序依次初始化.然而,自从程序员和工具可以随意安排变量的声明后,你不应该在依靠变量任何特别的次序初始化
对虚方法用两个阶段的构建.避免从一个构造器调用虚方法. 如果在初始化一个对象时需要调用一些虚方法,应在完整构造该对象的地方使用两阶段的构建,并随后调用已构造对象的初始化方法。
下面就是来自这个示例程序的控制台输出
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依据它们在源文件中的声明的顺序依次初始化.然而,自从程序员和工具可以随意安排变量的声明后,你不应该在依靠变量任何特别的次序初始化
对虚方法用两个阶段的构建.避免从一个构造器调用虚方法. 如果在初始化一个对象时需要调用一些虚方法,应在完整构造该对象的地方使用两阶段的构建,并随后调用已构造对象的初始化方法。