2010-09-26 9 views
63

Sous quelles conditions suis-je censé effectuer les appels constructeurs :base() et :this() 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?meilleures pratiques des constructeurs base() et this (

+0

désolé pour l'ambiguïté ... Je sais ce que ces appels font. Je n'étais pas clair sur le scénario quand je devrais ou dois faire ces appels. Des endroits où si je ne les fais pas alors je suis tout de suite condamné ou il y aura un bug latent, ou une mauvaise qualité de code. J'ai récemment eu un tel mal de tête donc je voulais clarifier ces scénarios. - – explorer

Répondre

85

: base(...)

Si vous omettez l'appel à un constructeur de base, il appellera 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 du constructeur par défaut. Dans ce cas, vous pouvez toujours utiliser base(foo, bar) pour appeler un constructeur différent du constructeur de base.

Je ne considère pas comme une mauvaise pratique d'omettre base() lorsque vous voulez appeler le constructeur par défaut de la classe de base, bien que si vous voulez être explicite, je ne vois pas de mal à 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. Il n'est jamais obligatoire de le faire, mais peut parfois être utile.

Un exemple de quand il peut être utile est de réutiliser le code commun dans les constructeurs. Par exemple, en C# 3.5 ou avant vous souhaitez 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 paramètres C# 4.0 sont maintenant disponibles en option ce qui réduit la nécessité de cette approche.

Une autre façon de réutiliser le code dans les constructeurs consiste à le factoriser dans une fonction statique appelée par chaque constructeur qui souhaite l'utiliser.

5

Rechercher "constructor chaining in C#". En fait, il ressemble à ceci:

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

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

Il aide à éliminer la duplication de code dans les constructeurs - les diviser en éléments de base et spécifiques.

+0

Merci. "Constructor Chaining" était le terme dont je ne me souvenais pas. – JNappi

4

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

En base :() et this(): vous pouvez transmettre comme paramètres des valeurs constantes, ou une expression basée 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 (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 

} 
28

Tout d'abord, quand ils sont obligatoires.

Lorsqu'une classe Derived est dérivée d'une classe Base et Base n'a pas de constructeur par défaut (sans paramètre), Derived doit appeler explicitement base() 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-il une bonne pratique? Chaque fois que vous voulez appeler un constructeur différent. Supposons que vous ajoutiez, dans mon exemple précédent, du contenu aux constructeurs dans 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); 
    } 
} 
+0

Ainsi, l'ordre d'appel dans le dernier exemple serait: 'base (7)', puis 'Derived (7)', et ensuite 'Derived()'. En d'autres termes, la partie 'this (7)' ne déclenchera pas elle-même 'base()' (en supposant qu'il y ait une telle méthode de base). Est-ce correct? – RayLuo

+1

Correct; les constructeurs sont toujours chaînés et chaque classe appelle les constructeurs de sa classe de base. En utilisant 'this', vous obtenez de réutiliser l'autre constructeur de cette classe (qui utilisera lui-même' base', soit implicitement sans arguments, soit explicitement); En utilisant 'base', vous pouvez choisir quel constructeur de classe de base appeler. – configurator

21

Utilisez base quand il y a l'héritage, et une classe mère fournit déjà la fonctionnalité que vous essayez d'atteindre. 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 une fonctionnalité déjà définie dans un autre constructeur.

Fondamentalement, en utilisant la base et ce, dans l'en-tête d'un constructeur est de garder votre code DRY, rendant plus maintenable et moins bavard

Voici un exemple tout à fait dénuée 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."); 
    } 
} 

Utilisation:

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.