DavidJGu's Blog

       尼采说,宁可追求虚无也不能无所追求!  Keeping is harder than winning
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C# 类初始化顺序

Posted on 2009-02-15 21:47  Let's DotNet  阅读(905)  评论(0编辑  收藏  举报

 看起来这是一个不太容易不被注意的一个问题,

 

using System;

class Foo
{
    public Foo(string s)
    {
        Console.WriteLine("Foo constructor: {0}", s);
    }
    public void Bar() { }
}
class Base
{
    readonly Foo baseFoo = new Foo("Base initializer");
    public Base()
    {
        Console.WriteLine("Base constructor");
    }
}
class Derived : Base
{
    readonly Foo derivedFoo = new Foo("Derived initializer");
    public Derived()
    {
        Console.WriteLine("Derived constructor");
    }
}
static class Program
{
    static void Main()
    {
        new Derived();
    }
}

 

 

 这段代码的实际输出是:

Foo constructor: Derived initializer
Foo constructor: Base initializer
Base constructor
Derived constructor

 

我觉得关键的注意点是,C#类需要确保类型(Type)正确性(避免有NULL),所以总是在一个类正式初始化之前进行成员的初始化,接下来的动作依次类推并递归。下面是比较合理的解释,

 

 

Process of creating an Instance of a Class goes in the following order: (static would be different)

Step 1) Compiler executes code related to instance variable declarations; this is to identify the fields required to construct the instance.

Step 2) Compiler executes the desired constructor - Constructor is the first method that is called on an instance.

Trick is here: To construct a Derived class instance a base class instance needs to be constructed.

Let’s get back to the code we are looking at:

1) Line 'new Derived();' of the 'static void Main()' method creates an instance of 'Derived' class. So the compiler should run Step 1 on 'Derived' class.

Result: 'Foo constructor: Derived initializer' is written to the console.

2) Compiler should run Step 2 on 'Derived' class. To create an instance of the derived class it first needs to construct the base class instance. Hence,

i) Step 1 is called on 'Base' class.

Result: 'Foo constructor: Base initializer' is written to the console.

ii) After Step 1, Step 2 is called on 'Base' class.

Result: 'Base constructor' is written to the console.

Since the Base class instance is constructed, it finishes with constructing the Derived class by calling Step 2 on the 'Derived' class

Result: 'Derived constructor' is written to the console.

 

 

 而在第二篇( http://blogs.msdn.com/ericlippert/archive/2008/02/18/why-do-initializers-run-in-the-opposite-order-as-constructors-part-two.aspx)中,更是有详细的例子解释说明如果不这样做的问题。(当然它来自不良的变成习惯)。

 

 对此C#初始顺序的解释(我想同样适合于Java),引起了很多C++用户的再次的“笑”评。其实,个中原因还是托管型语言希望拥有更稳定的解释执行环境,强调了“类型安全和检查”的方针执行,所以不能说谁好谁差。

 不过,倒是提醒我们在没有特殊的情况下,不要在构造函数外初始化成员变量,也许是一个好的习惯。

 

 

 

 原文:Why Do Initializers Run In The Opposite Order As Constructors

 http://blogs.msdn.com/ericlippert/archive/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one.aspx

 http://blogs.msdn.com/ericlippert/archive/2008/02/18/why-do-initializers-run-in-the-opposite-order-as-constructors-part-two.aspx