代码之家  ›  专栏  ›  技术社区  ›  Mike Comstock

C#中的基本构造函数-哪个首先被调用?[副本]

  •  143
  • Mike Comstock  · 技术社区  · 17 年前

    哪个先被调用——基础构造函数还是“这里的其他东西”?

    public class MyExceptionClass : Exception
    {
        public MyExceptionClass(string message, string extrainfo) : base(message)
        {
            //other stuff here
        }
    }
    
    13 回复  |  直到 17 年前
        1
  •  157
  •   Sam Meldrum    17 年前

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

    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文章:

        2
  •  119
  •   craigb    17 年前

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

    试试看:

    public class MyBase
    {
      public MyBase()
      {
        Console.WriteLine("MyBase");
      }
    }
    
    public class MyDerived : MyBase
    {
      public MyDerived():base()
      {
        Console.WriteLine("MyDerived");
      }
    }
    
        3
  •  45
  •   David Pokluda    17 年前

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

    (这是简化的,但它应该有助于你在将来回答这个问题,而不需要实际记住这一点。)

        4
  •  25
  •   Paolo Tedesco    17 年前

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

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

        5
  •  7
  •   Joel B Fant    17 年前

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

    假设你有这样的课程:

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

    首先,字段初始化器将按照从派生类最多到派生类最少的顺序调用。所以第一个字段初始化器 C 那么 B 那么 A .

    随后,构造函数将按照相反的顺序被调用:首先 A. 的构造函数,那么 B 那么 C .

        6
  •  5
  •   Dologan    17 年前

    我会说基地

    编辑请参见:

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

    该程序输出

    基地2

    派生类

        7
  •  3
  •   zwcloud    9 年前

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

    呼叫顺序为

    1. 派生类字段初始化器
    2. 基类字段初始化器
    3. 基类构造函数
    4. 派生类构造函数

    (您可以将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;
        }
    }
    

    包含多个变量初始化器;它还包含构造函数 两种形式的初始化器(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;
        }
    }
    
        8
  •  2
  •   Emperor XLII    17 年前

    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
  •   mmcdole    17 年前
        10
  •  1
  •   CheGueVerra    17 年前

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

    简单的OO原理

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

        11
  •  0
  •   kafuchau    17 年前

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

        12
  •  0
  •   Chris Cudmore    17 年前

    在子构造函数中完成任何工作之前调用base(?)。

    这是真的,即使你省略了:base()(在这种情况下,会调用0参数的base构造函数。)

    它的工作原理类似于java,

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

    ***例外:我可以输入super(1,2,3)。但如果我没有显式地调用super,就会调用super()。

        13
  •  0
  •   edirtyfour edirtyfour    17 年前

    构造函数调用从下往上调用(触发),并从上往下执行。因此,如果你有从继承自类A的类B继承的类C,当你创建类C的实例时,会调用C的构造函数,这反过来会调用B的指令,后者又会调用A的构造函数。现在执行A的构造函数,然后执行B的构造函数,然后执行C的构造函数。