Перегрузить «базовый» конструктор или «этот» конструктор? - PullRequest
7 голосов
/ 15 апреля 2009

У меня есть несколько типов, которые происходят от упрощенного Base, как показано ниже.

Я не уверен, использовать ли конструктор базового класса или this конструктор при перегрузке конструкторов.

ConcreteA перегружает конструкторы, просто используя конструкторы base, тогда как
ConcreteB перегрузок с использованием this для первых двух перегрузок.

Как лучше перегрузить конструкторы?

public abstract class Base
{
    public string Name { get; set; }
    public int? Age { get; set; }

    protected Base() : this(string.Empty) {}
    protected Base(string name) : this(name, null) {}
    protected Base(string name, int? age)
    {
        Name = name;
        Age = age;
    }
}

public class ConcreteA : Base
{
    public ConcreteA(){}
    public ConcreteA(string name) : base(name) {}
    public ConcreteA(string name, int? age) : base(name, age)
    {
    }
}

public class ConcreteB : Base
{
    public ConcreteB() : this(string.Empty, null){}
    public ConcreteB(string name): this(name, null){}
    public ConcreteB(string name, int? age) : base(name, age)
    {
    }
}

[Изменить] Похоже, что то, что предложил Ян Куигли в своем ответе 1019 *, казалось, имело смысл. Если бы у меня был вызов, который инициализирует валидаторы, ConcreteA(string) никогда не будет инициализировать валидаторы в следующем случае.

public class ConcreteA : Base
{
    public ConcreteA(){}
    public ConcreteA(string name) : base(name) {}
    public ConcreteA(string name, int? age) : base(name, age)
    {
        InitializeValidators();
    }
    private void InitializeValidators() {}
}

Ответы [ 6 ]

5 голосов
/ 15 апреля 2009

Это . Потому что, если вы когда-нибудь поместите код в ConcreteB (string, int?), Вы захотите, чтобы конструктор, содержащий только строки, вызывал его.

2 голосов
/ 15 апреля 2009

Хорошо смешивать и сочетать; в конечном счете, когда вы используете конструктор this(...), он в конечном итоге доберется до ctor, который сначала вызывает base(...). Имеет смысл повторно использовать логику там, где это необходимо.

Вы можете расположить его так, чтобы все конструкторы называли общий (может быть частный) this(...) конструктор, единственный, который вызывает base(...), но это зависит от того, полезно ли: и b: есть ли один base(...) ctor, который позволил бы вам.

2 голосов
/ 15 апреля 2009

В общем, я бы назвал это, а не основание. Вы, вероятно, будете использовать больше кода таким образом, если позже расширитесь.

1 голос
/ 15 апреля 2009

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

0 голосов
/ 15 апреля 2009

Спросите себя снова, почему вы перегружаете конструктор в Базовом классе? Этого достаточно:

protected Base()

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

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

0 голосов
/ 15 апреля 2009

Чтобы уменьшить сложность путей кода, я обычно стараюсь иметь ровно один вызов конструктора base() (случай ConcreteB). Таким образом, вы знаете, что инициализация базового класса всегда происходит одинаково.

Однако, в зависимости от класса, который вы переопределяете, это может оказаться невозможным или добавить ненужную сложность. Это справедливо для специальных шаблонов конструктора, таких как шаблон при реализации ISerializable .

...