C#构造函数执行顺序

时间:2009-12-10 17:40:47

标签: c# inheritance constructor constructor-chaining

在C#中,当你做

Class(Type param1, Type param2) : base(param1) 

是先执行的类的构造函数,然后调用超类构造函数还是首先调用基类构造函数?

8 个答案:

答案 0 :(得分:158)

订单是:

  • 成员变量初始化为层次结构中所有类的默认值

然后从派生程度最高的类开始:

  • 为最派生类型执行变量初始值设定项
  • 构造函数链接计算出将要调用的基类构造函数
  • 初始化基类(递归所有这些:)
  • 执行此类链中的构造函数体(请注意,如果它们与Foo() : this(...)链接在一起,则可以有多个

请注意,在Java中,在运行变量初始值设定项之前,基类已初始化为。如果您输入任何代码,这是一个重要的区别,知道:)

如果您有兴趣,我会page with more details

答案 1 :(得分:48)

它将首先调用基础构造函数。还要记住,如果你没有在构造函数之后放置:base(param1),那么将调用base的空构造函数。

答案 2 :(得分:12)

首先调用基类的构造函数。

答案 3 :(得分:7)

不确定这是否应该是评论/答案,但对于那些通过示例学习的人来说,这个小提琴也说明了顺序:https://dotnetfiddle.net/kETPKP

using System;

// order is approximately
/*
   1) most derived initializers first.
   2) most base constructors first (or top-level in constructor-stack first.)
*/
public class Program
{
    public static void Main()
    {
        var d = new D();
    }
}

public class A
{
    public readonly C ac = new C("A");

    public A()
    {
        Console.WriteLine("A");
    }
    public A(string x) : this()
    {
        Console.WriteLine("A got " + x);
    }
}

public class B : A
{
    public readonly C bc = new C("B");

    public B(): base()
    {
        Console.WriteLine("B");
    }
    public B(string x): base(x)
    {
        Console.WriteLine("B got " + x);
    }
}

public class D : B
{
    public readonly C dc = new C("D");

    public D(): this("ha")
    {
        Console.WriteLine("D");
    }
    public D(string x) : base(x)
    {
        Console.WriteLine("D got " + x);
    }
}

public class C
{
    public C(string caller)
    {
        Console.WriteLine(caller + "'s C.");
    }
}

结果:

D's C.
B's C.
A's C.
A
A got ha
B got ha
D got ha
D

答案 4 :(得分:1)

[编辑:在我回答的时候,这个问题已经彻底改变了]。

答案是它先调用基地。

[以下旧问题的原始答案]

您是否在询问何时执行构造函数调用的“基本”位?

如果是这样,如果该类派生自另一个具有此构造函数的类,则会“链接”对构造函数库的调用:

  public class CollisionBase
    {
        public CollisionBase(Body body, GameObject entity)
        {

        }
    }

    public class TerrainCollision : CollisionBase
    {
        public TerrainCollision(Body body, GameObject entity)
            : base(body, entity)
        {

        }
    }

在此示例中,TerrainCollision派生自CollisionBase。通过以这种方式链接构造函数,它确保使用提供的参数在基类上调用指定的构造函数,而不是默认构造函数(如果基础上有一个)

答案 5 :(得分:0)

您的问题有点不清楚,但我假设您打算提出以下问题

  

何时为XNA对象调用基础构造函数而不是使用impilict默认构造函数

对此的回答高度依赖于您的场景和底层对象。你能否澄清以下内容

  • 情景是什么
  • TerrainCollision的基础对象的类型是什么?

我最好的答案是,在你有参数与基类构造函数的参数对齐的情况下,你几乎肯定会调用它。

答案 6 :(得分:0)

构造函数机制更好,因为它使应用程序使用构造函数链接,如果您要扩展应用程序,它通过继承实现最小化代码更改的能力。 Jon Skeets Article

答案 7 :(得分:0)

巧合的是,这也是一个最常被问到的面试问题,并在此youtube video with demonstration中进行了解释。

首先不要试图记住顺序。 在父子关系中合乎逻辑地思考,子建立在父之上。所以显然应该先创建父实例,然后再创建子实例。

<块引用>

所以首先是父构造函数触发,然后是子构造函数。

但是,当涉及到初始化器时,情况有所不同。

<块引用>

对于初始化器,首先运行子初始化器,然后是父初始化器。

下面是相同的图形表示。所以构造函数代码从父到子触发,初始化器从子到父触发。

C# constructor execution