【问题标题】:C#: Order of Constructor callC#:构造函数调用的顺序
【发布时间】:2012-08-22 18:18:48
【问题描述】:

考虑以下代码:

代码

public class RecursiveConstructor
{
   //When this constructor is called 
   public RecursiveConstructor():this(One(), Two())
   {
       Console.WriteLine("Constructor one. Basic.");
   }

   public RecursiveConstructor(int i, int j)
   {
       Console.WriteLine("Constructor two.");
       Console.WriteLine("Total = " + (i+j));
   }

   public static int One()
   {
       return 1;
   }

   public static int Two()
   {
       return 2;
   }
}

调用方法

public class RecursiveConstructorTest
{
    public static void Main()
    {
        RecursiveConstructor recursiveConstructor = new RecursiveConstructor();

        Console.ReadKey();
    }
}

结果

构造函数二。

总计 = 3

构造函数一。基本。

为什么第二个构造函数首先运行?

我知道在链式构造函数中,我们首先调用基类构造函数,然后返回链,但是当构造函数保存在同一个类中时,为什么我们仍然会看到首先调用额外构造函数的这种行为?

本来以为会先执行最基本的构造函数内容。

【问题讨论】:

  • 顺便说一下,这不是递归的。
  • 我认为这仍然是构造函数链接。
  • 谢谢。认为它是递归构造函数是我的错误。我已批准对标题的编辑。所以我们在这里看到的本质上是构造函数链接,但在同一个类中,而不是跨继承和基类?
  • 我并不完全清楚你在问什么 - “为什么第二个构造函数首先运行?” - 因为您要求第二个先运行!如果你想要不同的行为,你需要编写不同的代码。

标签: c# constructor


【解决方案1】:

你自己给出了解释。调用基本构造函数的方式几乎相同。每当在您的签名中调用构造函数时,例如

 public RecursiveConstructor() : this(One(), Two())

 public RecursiveConstructor() : base()

: 之后的构造函数首先被调用。

【讨论】:

  • 在框架中这样编码是否有原因?
  • “原始”的无参数构造函数可以(例如)初始化一些属性或字段(其值可以在参数化构造函数中设置,然后不会引发空引用异常)。
  • @CSharpened 我无法解释为什么它是这样编码的。内部实现可能会立即在“:”之后调用构造函数,就像在 java 中一样。签名后的第一个关键字也称为“super()”或“this()”。
  • @CSharpened 我猜您可能希望能够从默认构造函数调用更具体的构造函数,以便能够传递默认值。使用: 调用它也会执行所有其他实例化,因此您知道在使用更通用的设置之前首先构造了该类。如果您愿意,当然也可以在默认构造函数中调用更具体的构造函数。
【解决方案2】:

我认为编译器运行更安全的方案。 如果你在这里调用另一个构造函数,那么这个构造函数很可能是你当前构造函数的先决条件。这种行为与调用基构造函数时暴露的行为一致,是可以预料的。

在创建类的新实例时,会调用一系列构造函数,从最不专业(对象类的构造函数)到最专业(当前类的构造函数)调用。

运算符: 允许您显式添加构造函数到此链中,因此此顺序看起来很自然。

【讨论】:

  • 另外:即使你没有明确地这样写,默认的 base() 构造函数总是在类的构造函数之前被调用,所以附加的 : this(..) 因此也会被首先调用。它与已经隐含的行为一致。
  • 是的,这是一个依赖链。 : 运算符用于显式地将元素添加到此依赖链。
【解决方案3】:

它首先调用构造函数 1,但 ctor1 在它到达 ctor1 代码块之前调用 ctor2,因此您会看到输出。

解决这个问题的一种方法,但要保留 DRY 行为是重构 (int, int) 重载:

   //When this constructor is called 
   public RecursiveConstructor()
   {
       Console.WriteLine("Constructor one. Basic.");
       Init(One(), Two());
   }

   public RecursiveConstructor(int i, int j)
   {
       Console.WriteLine("Ctor 2");
       Init(i, j);
   }


   private void Init(int i, int j)
   {
       Console.WriteLine("Refactored");
       Console.WriteLine("Total = " + (i+j));
   }

出于兴趣,以这种方式链接构造函数通常称为“delegating constructors”。

在 Java 中,可以在代码块中调用另一个构造函数(例如 see here),但它必须是代码块中的第一行

【讨论】:

    【解决方案4】:

    当您考虑到在初始化新对象时总是有一个层次结构的构造函数调用链时,这是有道理的。正如你所说的,首先调用基类构造函数。

    构造函数初始化器的两种形式,: base(...),通常被隐式调用,: this(...) 的行为方式相同。

    所以,在你的情况下,我们有一个链:

    Object()
    

    那么……

    RecursiveConstructor(int i, int j)
    

    那么……

    RecursiveConstructor()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-28
      • 1970-01-01
      • 2013-06-24
      • 2012-04-10
      • 1970-01-01
      • 2010-10-13
      • 2010-12-25
      相关资源
      最近更新 更多