调用静态构造函数和实例构造函数

F11*_*F11 6 c#

据我所知,父类的构造函数先调用然后调用子类.但是为什么在静态构造函数的情况下它首先从派生类执行,然后是子类?

namespace ConsoleApplication1

    {

 class Program

    {

        static void Main(string[] args)
        {
            Child t = new Child();
        }
    }

    class Parent
    {
        public  Parent()
        {
            Console.WriteLine("Parent Instance Constructor");
            Console.ReadKey();
        }

        static Parent()
        {
            Console.WriteLine("Parent Static Constructor");
            Console.ReadKey();
        }
    }
    class Child : Parent
    {
        public Child()
        {
            Console.WriteLine("Child Instance Constructor");
            Console.ReadKey();
        }

        static Child()
        {
            Console.WriteLine("Child Static Constructor");
            Console.ReadKey();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

子静态构造函数

父静态构造函数

父实例构造函数

子实例构造函数

现在按照Jeppe Stig Nielsen建议,当我在构造函数中初始化静态字段时,它按以下顺序运行

产量

父静态构造函数

子静态构造函数

父实例构造函数

子实例构造函数

class XyzParent
{
    protected static int FieldOne;
    protected int FieldTwo;

    static XyzParent()
    {
        // !  
        FieldOne = 1;
        Console.WriteLine("parent static");
    }
    internal XyzParent()
    {
        // !  
        FieldOne = 10;
        // !  
        FieldTwo = 20;
        Console.WriteLine("parent instance");
    }
}
class XyzChild : XyzParent
{
    static XyzChild()
    {
        // !  
        FieldOne = 100;
        Console.WriteLine("child static");
    }
    internal XyzChild()
    {
        // !  
        FieldOne = 1000;
        // !  
        FieldTwo = 2000;
        Console.WriteLine("child instance");
    }
}
Run Code Online (Sandbox Code Playgroud)

为何如此矛盾的行为呢?

Eri*_*ert 20

首先,这种行为完全不矛盾; 这一切都符合规则.你只是不知道规则是什么.

您应该阅读我关于实例构造函数的两部分系列文章以及关于静态构造函数语义的四部分系列文章.他们从这里开始:

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

和这里:

http://ericlippert.com/2013/02/06/static-constructors-part-one/

分别.

那些应该清楚地回答你的问题,但如果不是100%明确,请让我总结一下.相关规则是:

  • 规则一:静态构造函数在访问任何静态字段之前,执行任何静态方法之前,以及执行任何实例构造函数之前运行.
  • 规则二:派生类实例构造函数在运行派生类实例构造函数体之前调用基类实例构造函数.

那么当你执行时会发生什么new Child()

  • 第一条适用.我们将调用Child的实例构造函数,因此我们必须首先调用Child的静态构造函数.所以它首先运行.
  • 在Child的静态构造函数返回之后,Child的实例构造函数运行.规则二适用:Child实例构造函数在运行其主体之前所做的第一件事就是运行Parent的实例构造函数.
  • 规则一再适用.我们将调用Parent的实例构造函数,因此我们必须首先调用Parent的静态构造函数.所以它运行.
  • 在Parent的静态构造函数返回之后,Parent的实例构造函数运行.规则二适用:它调用object的实例构造函数,它没有任何兴趣,然后运行Parent的实例构造函数的主体.
  • Control返回Child的实例构造函数,并且其正文运行.

所以你去; 顺序是Child静态构造函数,然后是Parent静态构造函数,然后是Parent主体,然后是Child主体.

现在让我们看看你的第二个例子.你说什么会发生什么new XyzChild

  • 第一条适用.我们将调用XyzChild的实例构造函数,因此我们首先调用XyzChild的静态构造函数.它的身体开始执行,并且......
  • ......规则一再适用.我们将要访问XyzParent的静态字段,因此必须执行XyzParent的静态构造函数.
  • XyzParent的静态构造函数执行.它访问一个字段,但静态构造函数已经在这个线程上运行,因此它不会再次递归地触发静态构造函数.它打印出它在父母中.
  • 控制返回到子节点的静态构造函数,该构造函数打印出它在子节点中.
  • 现在孩子的实例构造函数可以运行了.规则二适用:XyzParent的实例构造函数首先运行.
  • 规则一适用,但XyzParent的静态构造函数已经运行,因此它被跳过.
  • XyzParent的实例构造函数的主体执行并将控制返回给XyzChild的静态构造函数.
  • XyzChild的实例构造函数的主体运行.

你去吧 没有任何不一致之处; 这两个规则正确应用.


Joh*_*Woo 6

Static构造函数总是在非静态构造函数之前执行.第一次访问类时调用静态构造函数.

来自MSDN Doc,

  • 静态构造函数不接受访问修饰符或具有参数.
  • 在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类.
  • 无法直接调用静态构造函数.用户无法控制何时在程序中执行静态构造函数.
  • 静态构造函数的典型用法是当类使用日志文件并且构造函数用于将条目写入此文件时.
  • 当构造函数可以调用LoadLibrary方法时,静态构造函数在为非托管代码创建包装类时也很有用.
  • 如果静态构造函数抛出异常,则运行时将不会再次调用它,并且该类型将在运行程序的应用程序域的生命周期内保持未初始化状态.