dotaeye

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一、C#中构造函数有几种。

1.静态构造函数

2.默认构造函数

3.带参数的构造函数

二、顺序如何执行呢?

先看代码:

 class MyClass
    {
        static MyClass()
        {
            Console.WriteLine("静态构造函数被调用。");
        }
        private static Component staticField = new Component("静态字段被实例化。");
        private Component instanceField = new Component("实例成员字段被实例化。");
        public MyClass()
        {
            Console.WriteLine("对象构造函数被调用。");
        }
    }

    //此类型用于作MyClass类的成员//此类型在实例化的时候可以再控制台输出自定义信息,以给出相关提示
    class Component
    {
        public Component(String info)
        {
            Console.WriteLine(info);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass instance = new MyClass();

            Console.Read();
        }
    }

  运行结果:

1.静态字段被实例化
2.静态构造函数被调用
3.实例成员字段被实例化
4.对象构造函数被调用

再来看看带基类的构造函数是如何运行

class Base
    {
        static Base()
        {
            Console.WriteLine("基类静态构造函数被调用。");
        }

        private static Component baseStaticField = new Component("基类静态字段被实例化。");
        private Component baseInstanceField = new Component("基类实例成员字段被实例化。");

        public Base()
        {
            Console.WriteLine("基类构造函数被调用。");
        }
    }

    //此类型用作派生类,同基类一样,它也包含静态构造函数,以及静态字段、实例成员字段各一个。
    class Derived : Base
    {
        static Derived()
        {
            Console.WriteLine("派生类静态构造函数被调用。");
        }

        private static Component derivedStaticField = new Component("派生类静态字段被实例化。");
        private Component derivedInstanceField = new Component("派生类实例成员字段被实例化。");

        public Derived()
        {
            Console.WriteLine("派生类构造函数被调用。");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
     
            Derived derivedObject = new Derived();

            Console.Read();
        }
    }

  

  运行结果:

1.派生类静态字段被实例化

2.派生类静态构造函数被调用

3.派生类实例成员字段被实例化

4.基类静态字段被实例化

5.基类类静态构造函数被调用

6.基类实例成员字段被实例化

7.派生类对象构造函数被调用

三、结论

1.对于代码1中的实例分析:

静态构造函数和静态字段的构造函数会首先被调用。

因为CLR在使用任何类型实例之前一定会先装载该类型,也就需要调用静态构造函数并且初始化静态成员。

但是,到底是先初始化静态成员呢,还是调用静态构造函数呢?

答案是初始化静态成员,因为CLR必须保证在执行构造函数的方法体时,相关的成员变量应该都可以被安全地使用。同样的道理也适用于实例构造函数和字段,也就是说对象成员的实例化会先于成员构造函数被执行。

顺便说一句,类定义直接初始化类\对象字段的功能是由类\对象字段初始化器完成的。

2.对于代码2中的实例分析:

从结果我们可以看出,派生类的静态字段初始化,静态构造函数调用,实例成员字段初始化都会先于基类的任何初始化动作被执行。对于派生类静态部分先被构造这一点比较容易理解,因为毕竟在CLR装载派生类Derived之前,基类Base还未被使用过,也就不会先被装载。

但是,为什么派生类的实例成员字段会在基类被构造之前被初始化呢?

答案和虚函数有关。试想有这么一个基类,它在构造函数中调用了一个虚方法。然后又有这么一个派生类,它重写了基类的那个虚方法,并且在这个虚方法中访问了它自己的一个实例成员字段。这一切都是完全合法的(至少在C#的世界里是这样的),对吧?在实例化一个派生类对象的过程中,其基类的构造函数会被调用,接着那个虚方法也会被调用,再接着派生类的实例成员字段会被访问。所以此时此刻,这个类的实例成员字段必须是已被准备好了的!因此,派生类的实例成员字段必须先于基类部分被构造。

好了,再回到我们的例子。剩下的部分很容易理解:基类按照我们预想的方式被生成,然后派生类的构造函数被调用。至此,一个派生类的对象就被实例化了。

顺便说一句,关于类字段初始化器,或对象字段初始化器,他们初始化成员字段的顺序是成员在类定义中出现的先后顺序。再顺便说一句,如果程序的逻辑依赖于成员在类定义中出现的顺序则是不好的设计,这可能会大大降低您代码的易读性。

 

posted on 2013-02-19 14:29  dotaeye  阅读(1004)  评论(0编辑  收藏  举报