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

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

  •  109
  • Mike Comstock  · 技术社区  · 16 年前

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

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

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

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

        2
  •  119
  •   craigb    16 年前

    试试看:

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

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

        4
  •  25
  •   Paolo Tedesco    16 年前

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

        5
  •  7
  •   Joel B Fant    16 年前

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

    假设你有这样的课程:

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

    首先,字段初始值设定项将按从派生最多的类到派生最少的类的顺序调用。所以第一个字段的初始值设定项 C B 然后 A .

    然后将以相反的顺序调用构造函数:First 那么,是的构造函数 B C

        6
  •  5
  •   Dologan    16 年前

    我说是基地

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

    此程序输出

    派生类

        7
  •  3
  •   zwcloud    8 年前

    首先调用基构造函数。但派生类中字段的初始值设定项是首先调用的。

    呼叫命令是

    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 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;
        }
    }
    
        8
  •  2
  •   Emperor XLII    16 年前

    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

        10
  •  1
  •   CheGueVerra    16 年前

    将调用异常构造函数,然后将调用子类构造函数。

    简单面向对象原则

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

        11
  •  0
  •   kafuchau    16 年前

    将首先调用基构造函数,否则,在“其他东西”必须使用基构造函数初始化的成员变量的情况下,将出现编译时错误,因为类成员尚未初始化。

        12
  •  0
  •   Chris Cudmore    16 年前

    它的工作原理类似于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    16 年前

    构造函数调用从下到上调用(激发),从上到下执行。因此,如果C类继承自B类,B类继承自A类,当您创建C类的实例时,会调用C类的构造函数,C类的构造函数会调用B类的讲师,B类的讲师会再次调用A类的构造函数。现在执行A类的构造函数,然后执行B类的构造函数,然后执行C的构造函数。