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

哪个被调用第一个 – 基础构造函数或“其他的东西在这里”?

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

基础构造函数将被首先调用。

尝试一下:

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

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

 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。

看看这2个MSDN文章:

  • 为什么初始化器与构造器的运行顺序相反? 第一部分
  • 为什么初始化器与构造器的运行顺序相反? 第二部分

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

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

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

所以:派生是首先执行,但它看起来像“基地先执行。

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

假设你有这样的课程:

 class A {} class B : A {} class C : B {} 

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

然后按照相反的顺序调用构造函数:First A的构造函数,然后是B ,然后是C

我会说基地

编辑见:

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

派生类

Exception构造函数将被调用,那么你的Child类构造函数将被调用。

简单的OO原则

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

Eric Lippert在对象初始化的相关问题上有一个有趣的post,它解释了构造函数和字段初始值设定项sorting的原因:

为什么初始化函数以相反的顺序作为构造函数运行? 第一部分
为什么初始化函数以相反的顺序作为构造函数运行? 第二部分

首先调用基构造器。 但派生类中的字段的初始化器首先被调用。

呼叫顺序是

  1. 派生类字段初始值设定项
  2. 基类字段初始值设定项
  3. 基类构造函数
  4. 派生类的构造函数

(你可以把2和3作为一个整体来构造基类。)

取自CSharp Language Speification 5.0

10.11.3构造器执行

variables初始化器被转换为赋值语句,这些赋值语句在调用基类实例构造函数之前执行。 这种sorting可以确保所有实例字段都在执行任何有权访问该实例的语句之前由其variables初始化器初始化。 举个例子

 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()来创buildB一个实例时,会产生以下输出:

 x = 1, y = 0 

x的值是1,因为在调用基类实例构造函数之前执行variables初始值设定项。 但是, y的值是0(一个int的默认值),因为直到基类构造函数返回之后才会执行对y的赋值。 将实例variables初始值设定项和构造函数初始值设定项视为在构造函数体之前自动插入的语句是很有用的。 这个例子

 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; } } 

包含几个variables初始化器; 它也包含两种forms(base和this)的构造函数初始值设定项。 该示例对应于下面显示的代码,其中每个注释表示自动插入的语句(用于自动插入的构造函数调用的语法无效,但仅用于说明机制)。

 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; } } 

基础构造函数将被首先调用,否则,在“其他的东西”必须使用基础构造函数初始化的成员variables的情况下,你会得到编译时错误,因为你的类成员还没有被初始化。

在子构造函数中完成任何工作之前调用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()。

构造函数调用从下到上被调用(触发),并从上到下执行。 因此,如果你有从inheritance自类A的类Binheritance的类C,当你创build一个类C的实例时,调用C的构造函数,继而调用B的教师,然后又调用构造函数A.现在执行A的构造函数,然后执行B的构造函数,然后执行C的构造函数。