C#中的基础构造函数 - 首先被调用?

时间:2008-09-26 16:17:42

标签: c# .net asp.net

首先调用哪个 - 基础构造函数或“其他东西在这里”?

public class MyExceptionClass : Exception
{
    public MyExceptionClass(string message, string extrainfo) : base(message)
    {
        //other stuff here
    }
}

13 个答案:

答案 0 :(得分:139)

在派生类构造函数之前调用基类构造函数,但在基类初始化程序之前调用派生类初始化程序。例如。在以下代码中:

public class BaseClass {

    private string sentenceOne = null;  // A

    public BaseClass() {
        sentenceOne = "The quick brown fox";  // B
    }
}

public class SubClass : BaseClass {

    private string sentenceTwo = null; // C

    public SubClass() {
        sentenceTwo = "jumps over the lazy dog"; // D
    }
}

执行顺序为:C,A,B,D。

查看这两篇msdn文章:

答案 1 :(得分:104)

首先调用基础构造函数。

试一试:

public class MyBase
{
  public MyBase()
  {
    Console.WriteLine("MyBase");
  }
}

public class MyDerived : MyBase
{
  public MyDerived():base()
  {
    Console.WriteLine("MyDerived");
  }
}

答案 2 :(得分:33)

不要试图记住它,试着向自己解释一下会发生什么。想象一下,你有一个名为Animal的基类和一个名为Dog的派生类。派生类为基类添加了一些功能。因此,当执行派生类的构造函数时,基类实例必须可用(以便您可以向其添加新功能)。这就是为什么构造函数从基础执行到派生但是析构函数以相反的方式执行 - 首先是派生的析构函数,然后是基础析构函数。

(这是简化的,但它可以帮助你在将来回答这个问题,而不需要实际记住它。)

答案 3 :(得分:21)

实际上,首先执行派生类构造函数,但C#编译器会将对基类构造函数的调用作为派生构造函数的第一个语句插入。

所以:派生首先被执行,但它“看起来像”首先执行了基础。

答案 4 :(得分:5)

正如其他人所说,首先调用基础构造函数。然而,构造函数并不是第一件事。

假设你有这样的课程:

class A {}

class B : A {}

class C : B {}

首先,将按照从大多数派生到最少派生类的顺序调用字段初始值设定项。首先是C的字段初始值设定项,然后是B,然后是A

然后将以相反的顺序调用构造函数:首先是A的构造函数,然后是B,然后是C

答案 5 :(得分:4)

我会说基础

编辑见:

http://www.c-sharpcorner.com/UploadFile/rajeshvs/ConsNDestructorsInCS11122005010300AM/ConsNDestructorsInCS.aspx

它说:

using System;
class Base
{

public Base()
{
    Console.WriteLine("BASE 1");
}
public Base(int x)
{
    Console.WriteLine("BASE 2");
}
}

class Derived : Base
{
public Derived():base(10)
{
    Console.WriteLine("DERIVED CLASS");
}
}

class MyClient
{
public static void Main()
{
    Derived d1 = new Derived();
}
}
  

该程序输出

     

BASE2

     

派生类

答案 6 :(得分:1)

答案 7 :(得分:1)

将调用Exception构造函数,然后将调用您的Child类构造函数。

简单OO原则

看看这里 http://www.dotnet-news.com/lien.aspx?ID=35151

答案 8 :(得分:1)

Eric Lippert在关于对象初始化的相关问题上有一篇有趣的文章,它解释了构造函数和字段初始化程序排序的原因:

Why Do Initializers Run In The Opposite Order As Constructors? Part One
Why Do Initializers Run In The Opposite Order As Constructors? Part Two

答案 9 :(得分:1)

首先调用Base Constructor。但是派生类中字段的初始化器首先被调用。

致电订单是

  1. 派生类字段初始值设定项
  2. 基类字段初始值设定项
  3. 基类构造函数
  4. 派生类构造函数
  5. (您可以将2和3作为一个整体来构建基类。)

    取自CSharp Language Speification 5.0

      

    10.11.3构造函数执行

         

    将变量初始值设定项转换为赋值语句和这些赋值   语句在调用基类之前执行   实例构造函数。此排序可确保所有实例字段   在任何语句之前由它们的变量初始值设定项初始化   有权访问该实例的人。给出例子

    using System;
    class A
    {
        public A() {
            PrintFields();
        }
        public virtual void PrintFields() {}
    }
    class B: A
    {
        int x = 1;
        int y;
        public B() {
            y = -1;
        }
        public override void PrintFields() {
            Console.WriteLine("x = {0}, y = {1}", x, y);
        }
    }
    
         

    new B()用于创建B的实例时,如下所示   输出产生:

    x = 1, y = 0
    
         

    x的值为1,因为执行了变量初始值设定项   在调用基类实例构造函数之前。然而   y的值为0(int的默认值),因为赋值   在基类构造函数返回之后才会执行y。   考虑实例变量初始化器和   构造函数初始值设定项作为自动插入的语句   在构造函数体之前。例子

    using System;
    using System.Collections;
    class A
    {
        int x = 1, y = -1, count;
        public A() {
            count = 0;
        }
        public A(int n) {
            count = n;
        }
    }
    class B: A
    {
        double sqrt2 = Math.Sqrt(2.0);
        ArrayList items = new ArrayList(100);
        int max;
        public B(): this(100) {
            items.Add("default");
        }
        public B(int n): base(n – 1) {
            max = n;
        }
    }
    
         

    包含几个变量初始值设定项;它还包含构造函数   两种形式的初始化者(基础和此)。该示例对应于   下面显示的代码,每个注释自动指示   inserted语句(用于自动插入的语法)   构造函数调用无效,但仅用于   说明机制)。

    using System.Collections;
    class A
    {
        int x, y, count;
        public A() {
            x = 1;                                // Variable initializer
            y = -1;                               // Variable initializer
            object();                         // Invoke object() constructor
            count = 0;
        }
        public A(int n) {
            x = 1;                                // Variable initializer
            y = -1;                               // Variable initializer
            object();                         // Invoke object() constructor
            count = n;
        }
    }
    class B: A
    {
        double sqrt2;
        ArrayList items;
        int max;
        public B(): this(100) {
            B(100);                               // Invoke B(int) constructor
            items.Add("default");
        }
        public B(int n): base(n – 1) {
            sqrt2 = Math.Sqrt(2.0);           // Variable initializer
            items = new ArrayList(100);   // Variable initializer
            A(n – 1);                         // Invoke A(int) constructor
            max = n;
        }
    }
    

答案 10 :(得分:0)

首先调用基础构造函数,否则,如果你的“其他东西”必须使用由基础构造函数初始化的成员变量,你将会遇到编译时错误,因为你的类成员还没有被初始化。

答案 11 :(得分:0)

在子构造函数中完成任何工作之前调用

base(?)。

这是事实,即使你不使用:base()(在这种情况下,调用0参数基础构造函数。)

它与java类似,

public Child()
{
   super(); // this line is always the first line in a child constructor even if you don't put it there! ***
}

***例外:我可以放入超级(1,2,3)。但是如果我没有明确地调用super,那么会调用super()。

答案 12 :(得分:0)

构造函数调用从下向上调用(触发),并从上到下执行。因此,如果你的C类继承自继承自A类的B类,那么当你创建C类的实例时,会调用C的构造函数,然后调用B的指令,B再次调用构造函数A.现在执行A的构造函数,然后执行B的构造函数,然后执行C的构造函数。