Порядок выполнения конструктора C#

В C#, когда вы делаете

Class(Type param1, Type param2) : base(param1) 

сначала выполняется конструктор класса, а затем вызывается конструктор суперкласса или сначала вызывается базовый конструктор?

8 ответов

Решение

Заказ:

  • Переменные-члены инициализируются значениями по умолчанию для всех классов в иерархии

Затем, начиная с самого производного класса:

  • Инициализаторы переменных выполняются для самого производного типа
  • Цепочка конструктора определяет, какой конструктор базового класса будет вызываться
  • Базовый класс инициализирован (рекурсивно все это:)
  • Тела конструктора в цепочке в этом классе выполняются (обратите внимание, что их может быть несколько, если они связаны Foo() : this(...) так далее

Обратите внимание, что в Java базовый класс инициализируется до запуска инициализаторов переменных. Если вы когда-нибудь портируете какой-либо код, об этом важно знать:)

У меня есть страница с более подробной информацией, если вам интересно.

Сначала он вызовет базовый конструктор. Также имейте в виду, что если вы не поставите :base(param1) после вашего конструктора будет вызываться пустой конструктор базы.

Не уверен, что это должен быть комментарий / ответ, но для тех, кто изучает на примере, эта скрипка также иллюстрирует порядок: https://dotnetfiddle.net/kETPKP

using System;

// order is approximately
/*
   1) most derived initializers first.
   2) most base constructors first (or top-level in constructor-stack first.)
*/
public class Program
{
    public static void Main()
    {
        var d = new D();
    }
}

public class A
{
    public readonly C ac = new C("A");

    public A()
    {
        Console.WriteLine("A");
    }
    public A(string x) : this()
    {
        Console.WriteLine("A got " + x);
    }
}

public class B : A
{
    public readonly C bc = new C("B");

    public B(): base()
    {
        Console.WriteLine("B");
    }
    public B(string x): base(x)
    {
        Console.WriteLine("B got " + x);
    }
}

public class D : B
{
    public readonly C dc = new C("D");

    public D(): this("ha")
    {
        Console.WriteLine("D");
    }
    public D(string x) : base(x)
    {
        Console.WriteLine("D got " + x);
    }
}

public class C
{
    public C(string caller)
    {
        Console.WriteLine(caller + "'s C.");
    }
}

Результат:

D's C.
B's C.
A's C.
A
A got ha
B got ha
D got ha
D

Конструктор базового класса вызывается первым.

По совпадению, это также наиболее часто задаваемый вопрос в интервью, и он объясняется в этом видео на YouTube с демонстрацией .

Первым делом не пытайтесь запомнить последовательность. Подумайте логически в отношениях родитель-ребенок, ребенок строится на вершине родителя. Итак, очевидно, что сначала должен быть создан родительский экземпляр, а затем дочерний.

Итак, сначала запускается родительский конструктор, а затем дочерний конструктор.

Но подождите, есть поворот, когда дело доходит до инициализаторов, все по-другому.

Для инициализаторов сначала запускаются дочерние инициализаторы, а затем родительские инициализаторы.

Ниже приведено схематическое изображение того же самого. Таким образом, код конструктора запускает родительский элемент в дочерний, а инициализаторы запускаются от дочернего элемента к родительскому.

[Изменить: за время, которое потребовалось мне, чтобы ответить, вопрос полностью изменился].

Ответ в том, что сначала она вызывает базу.

[Оригинальный ответ на старый вопрос ниже]

Вы спрашиваете, когда бы вы сделали "базовый" бит вызова конструктора?

Если это так, вы бы "связали" вызов с базой конструктора, если класс является производным от другого класса, который имеет этот конструктор:

  public class CollisionBase
    {
        public CollisionBase(Body body, GameObject entity)
        {

        }
    }

    public class TerrainCollision : CollisionBase
    {
        public TerrainCollision(Body body, GameObject entity)
            : base(body, entity)
        {

        }
    }

В этом примере TerrainCollision происходит от CollisionBase, Путем объединения конструкторов таким образом, он гарантирует, что указанный конструктор вызывается в базовом классе с предоставленными параметрами, а не в конструкторе по умолчанию (если он есть в базе)

Ваш вопрос немного неясен, но я предполагаю, что вы хотели спросить следующее

Когда я вызываю базовый конструктор для моего объекта XNA, вместо использования конструктора impilict по умолчанию

Ответ на этот вопрос сильно зависит как от вашего сценария, так и от базового объекта. Не могли бы вы уточнить немного со следующим

  • Какой сценарий
  • Каков тип базового объекта TerrainCollision?

Мой лучший ответ, однако, заключается в том, что в случае, когда у вас есть параметры, совпадающие с параметрами конструктора базового класса, вы почти наверняка должны вызывать его.

Механизм конструктора намного лучше, так как он оставляет приложение для использования цепочки конструктора, и если вы расширяете приложение, оно позволяет через наследование возможность вносить минимальные изменения кода. Статья Джона Скитса

Другие вопросы по тегам