Лучшие практики конструкторов base () и this () - PullRequest
76 голосов
/ 26 сентября 2010

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

Ответы [ 5 ]

98 голосов
/ 26 сентября 2010

: 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 теперь доступны дополнительные параметры, что снижает необходимость в этом подходе.

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

33 голосов
/ 26 сентября 2010

Прежде всего, когда они обязательны.

Когда класс 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);
    }
}
29 голосов
/ 26 сентября 2010

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

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

По сути, с использованием base, и это в заголовке конструктора - для сохранения вашего кода. СУХОЙ , что делает его более понятным и менее многословным

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

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.
8 голосов
/ 26 сентября 2010

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

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

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

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

4 голосов
/ 26 сентября 2010

Вы используете: 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

}
...