Лучшие практики конструкторов base() и this()

При каких условиях я должен сделать :base() а также :this() вызовы конструктора, следующие за скобками моего конструктора (или даже в других местах кода). Когда эти призывы являются передовой практикой и когда они являются обязательными?

5 ответов

Решение

: base(...)

Если вы пропустите вызов базового конструктора, он автоматически вызовет базовый конструктор по умолчанию.

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

Даже если есть конструктор по умолчанию, вы все равно можете вызвать конструктор, отличный от конструктора по умолчанию. В этом случае вы все еще можете использовать base(foo, bar) вызвать другой конструктор, чем базовый конструктор.

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

: this(...)

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

Примером, когда это может быть полезно, является повторное использование общего кода в конструкторах. Например, в C# 3.5 или перед тем, как вы захотите смоделировать необязательные параметры в конструкторе:

Foo(int x, int y)
{
     this.x = x;
     this.y = y;
}

Foo(int x) : this(x, 10) {}  // y defaults to 10

С C# 4.0 теперь доступны дополнительные параметры, что уменьшает потребность в таком подходе.

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

Использование base когда есть наследование, и родительский класс уже обеспечивает функциональность, которую вы пытаетесь достичь.

использование this когда вы хотите сослаться на текущий объект (или себя), используйте его в заголовке / подписи конструктора, если вы не хотите дублировать функциональность, которая уже определена в другом конструкторе.

По сути, использование base и this в заголовке конструктора делает ваш код СУХИМЫМ, делая его более понятным и менее многословным.

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

class Person
{
    public Person(string name)
    {
        Debug.WriteLine("My name is " + name);
    }
}

class Employee : Person
{
    public Employee(string name, string job)
        : base(name)
    {
        Debug.WriteLine("I " + job + " for money.");
    }

    public Employee() : this("Jeff", "write code")
    {
        Debug.WriteLine("I like cake.");
    }
}

Использование:

var foo = new Person("ANaimi");
// output:
//  My name is ANaimi

var bar = new Employee("ANaimi", "cook food");
// output:
//  My name is ANaimi
//  I cook food for money.

var baz = new Employee();
// output:
//  My name is Jeff
//  I write code for money.
//  I like cake.

Во-первых, когда они обязательны.

Когда класс Derived происходит от класса Base, а также Base не имеет конструктора по умолчанию (без параметров), Derived должен позвонить base() явно с параметрами.

public class Base {
    public Base(int i) { }
}


public class Derived : Base {
    // public Derived() { } wouldn't work - what should be given for i?
    public Derived() : base(7) { }
    public Derived(int i) : base(i) { }
}

Когда это хорошая практика? Всякий раз, когда вы хотите вызвать другой конструктор.

Предположим, вы добавили, в моем предыдущем примере, содержимое к конструкторам в Derived.

public class Derived : Base {
    // public Derived() { } wouldn't work - what should be given for i?
    public Derived() : base(7) {
        Console.WriteLine("The value is " + 7);
    }
    public Derived(int i) : base(i) {
        Console.WriteLine("The value is " + i);
    }
}

Вы заметили дублирование здесь? Проще вызвать конструктор this().

public class Derived : Base {
    // public Derived() { } wouldn't work - what should be given for i?
    public Derived() : this(7) { }
    public Derived(int i) : base(i) {
        Console.WriteLine("The value is " + i);
    }
}

Ищите "конструктор цепочки в C#". В основном это выглядит так:

MyClass():base()  //default constructor calling superclass constructor
{
}

MyClass(int arg):this()  //non-basic constructor calling base constructor
{
    //extra initialization
}

Это помогает убрать дубликаты кода в конструкторах - разбить их на базовые и специфические части.

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

В base:() и this(): вы можете передавать в качестве параметров постоянные значения или выражения, основанные на параметрах вашего конструктора.

Обязательно вызывать базовый конструктор, когда базовый класс не имеет конструктора по умолчанию (тот, который не принимает параметров). Я не знаю случая, в котором: this () является обязательным.

public class ABaseClass
{
    public ABaseClass(string s) {}
}

public class Foo : AChildClass
{
    public AChildClass(string s) : base(s) {} //base mandatory
    public AChildClass() : base("default value") {}  //base mandatory
    public AChildClass(string s,int i) : base(s+i) {}  //base mandatory
}

public class AnotherBaseClass
{
    public ABaseClass(string s) {}
    public ABaseClass():this("default value") {} //call constructor above
}

public class Foo : AnotherChildClass
{
    public AnotherChildClass(string s) : base(s) {} //base optional

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