web-dev-qa-db-fra.com

Bonnes pratiques des constructeurs base () et this ()

Dans quelles conditions suis-je censé faire les appels de constructeur :base() et :this() en suivant les parenthèses de mon constructeur (ou même à d'autres endroits du code). Quand ces appels sont-ils de bonnes pratiques et quand sont-ils obligatoires?

77
explorer

: base(...)

Si vous omettez l'appel d'un constructeur de base, celui-ci appelle automatiquement le constructeur de base par défaut.

Il est obligatoire d'appeler explicitement un constructeur de base s'il n'y a pas de constructeur par défaut.

Même s'il existe un constructeur par défaut, vous pouvez toujours appeler un constructeur différent de celui par défaut. Dans ce cas, vous pouvez toujours souhaiter utiliser base(foo, bar) pour appeler un constructeur différent de celui de base.

Je ne considère pas comme une mauvaise pratique d'omettre base() lorsque vous souhaitez appeler le constructeur par défaut de la classe de base, bien que, si vous aimez être explicite, je ne vois aucun inconvénient à l'inclure. C'est une question de goût.

: this(...)

Cette syntaxe vous permet d'appeler un constructeur avec une signature différente d'un autre dans la même classe. Cela n’est jamais obligatoire, mais cela peut parfois être utile.

Un exemple de moment où cela peut être utile concerne la réutilisation de code commun dans les constructeurs. Par exemple, dans C # 3.5 ou avant, vous souhaiterez peut-être simuler des paramètres facultatifs sur un constructeur:

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

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

Avec C # 4.0, des paramètres optionnels sont maintenant disponibles, ce qui réduit le besoin de cette approche.

Une autre façon de réutiliser le code dans les constructeurs consiste à l'intégrer à une fonction statique appelée à partir de chaque constructeur souhaitant l'utiliser.

98
Mark Byers

Tout d'abord, quand ils sont obligatoires.

Lorsqu'une classe Derived est dérivée d'une classe Base et que Base ne possède pas de constructeur par défaut (sans paramètre), Derived doit appeler base() explicitement avec des paramètres.

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) { }
}

Quand est-ce une bonne pratique? Chaque fois que vous souhaitez appeler un constructeur différent.

Supposons que vous ajoutiez, dans mon exemple précédent, du contenu aux constructeurs de 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);
    }
}

Vous remarquez la duplication ici? Il est plus simple d'appeler le constructeur 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);
    }
}
34
configurator

Utilisez base en cas d'héritage, et une classe parent fournit déjà les fonctionnalités que vous essayez d'atteindre.

Utilisez this lorsque vous souhaitez référencer l'entité actuelle (ou self), utilisez-la dans l'en-tête/la signature du constructeur lorsque vous ne souhaitez pas dupliquer la fonctionnalité déjà définie dans un autre constructeur.

Fondamentalement, en utilisant base et ceci dans l'en-tête du constructeur est de garder votre code SEC , ce qui le rend plus facile à gérer et moins bavard

Voici un exemple absolument dépourvu de sens, mais je pense qu’il illustre l’idée de montrer comment les deux peuvent être utilisés.

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.");
    }
}

Usage:

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.
30
ANaimi

Recherchez "constructeur chaînant en C #". En gros, ça ressemble à ça:

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

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

Il est utile d’éliminer la duplication de code dans les constructeurs - divisez-les en parties de base et spécifiques.

8
alxx

Vous utilisez: base () lorsque vous souhaitez que le constructeur de la classe de base soit automatiquement appelé en tant que première instruction de votre constructeur. : this () est similaire, mais appelle un autre constructeur sur la même classe.

En base :() et this (): vous pouvez passer en tant que paramètres des valeurs constantes ou des expressions basées sur les paramètres de votre constructeur.

Il est obligatoire d'appeler le constructeur de base lorsque la classe de base n'a pas de constructeur par défaut (un constructeur qui ne prend aucun paramètre). Je ne connais pas de cas dans lequel: this () est obligatoire.

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

}
4
Andrea Parodi