Devrions-nous toujours inclure un constructeur par défaut dans la classe?

Un collègue m’a posé cette question: devrions-nous toujours inclure un constructeur par défaut dans une classe? Si oui, pourquoi? Si non, pourquoi pas?

Exemple

public class Foo { Foo() { } Foo(int x, int y) { ... } } 

Je suis également intéressé par les experts.

Vous devez garder à l’esprit que si vous ne fournissez pas un constructeur surchargé, le compilateur générera un constructeur par défaut pour vous. Cela signifie que si vous avez juste

 public class Foo { } 

Le compilateur générera ceci comme:

 public class Foo { public Foo() { } } 

Cependant, dès que vous ajoutez l’autre constructeur

 public class Foo { public Foo(int x, int y) { // ... } } 

Le compilateur ne générera plus automatiquement le constructeur par défaut pour vous. Si la classe était déjà utilisée dans un autre code reposant sur la présence d’un constructeur par défaut, Foo f = new Foo(); , ce code va maintenant casser.

Si vous ne voulez pas que quelqu’un puisse initialiser la classe sans fournir de données, vous devez créer un constructeur par défaut, private pour être explicite sur le fait que vous empêchez la création des instances sans données d’entrée.

Cependant, il est parfois nécessaire de fournir un constructeur par défaut (public ou privé). Comme mentionné précédemment, certains types de sérialisation nécessitent un constructeur par défaut. Il y a aussi des moments où une classe possède plusieurs constructeurs paramétrés, mais nécessite également une initialisation de “niveau inférieur”, auquel cas un constructeur privé par défaut peut être utilisé et enchaîné à partir des constructeurs paramétrés.

 public class Foo { private Foo() { // do some low level initialization here } public Foo(int x, int y) : this() { // ... } public Foo(int x, int y, int z) : this() { // ... } } 

Certaines choses (comme la sérialisation) nécessitent un constructeur par défaut. En dehors de cela, cependant, un constructeur par défaut ne devrait être ajouté que si cela a du sens.

Par exemple, si les propriétés Foo.X et Foo.Y sont immuables après la construction, un constructeur par défaut n’a pas vraiment de sens. Même s’il devait être utilisé pour un Foo ‘vide’, un accesseur statique Empty serait plus accessible.

Je dirais non , certainement pas toujours . Supposons que vous ayez une classe avec des champs en lecture seule qui doivent être initialisés à une certaine valeur, et qu’il n’y a pas de valeurs par défaut raisonnables (ou vous ne voulez pas qu’il y en ait)? Dans ce scénario, je ne pense pas qu’un constructeur sans paramètre ait un sens.

Avoir un constructeur par défaut n’est qu’une bonne idée s’il est logique d’avoir un tel object.

Si vous produisez un object qui n’est pas dans un état valide d’un tel constructeur, la seule chose qu’il peut faire est d’introduire un bogue.

En guise de note, lorsque vous utilisez struct au lieu de class, notez qu’il n’y a aucun moyen de laisser le constructeur par défaut, ni de le définir vous-même, donc quels que soient les constructeurs que vous définissez, assurez-vous que l’état par défaut du struct (lorsque toutes les variables sont définies sur leur état par défaut (généralement 0 pour les types de valeur et null pour les types de référence), votre implémentation de la structure ne sera pas interrompue.

Oui, il est préférable d’avoir un constructeur par défaut pour éviter toute confusion. J’ai vu des gens qui ne font rien dans un constructeur par défaut (même dans les classes de Microsoft), mais qui aiment tout de même le garder car les objects sont automatiquement définis par défaut. Les classes qui ne spécifient pas de constructeur par défaut, .NET les appenda automatiquement pour vous.

La sérialisation a besoin d’un constructeur par défaut si vous utilisez des sérialiseurs existants, car cela a du sens pour les sérialiseurs à usage général, sinon vous devez créer votre propre implémentation.

Dans la plupart des cas, un constructeur par défaut est une bonne idée. Mais puisque vous utilisez le mot “toujours”, tout ce dont vous avez besoin est un contre-exemple. Si vous regardez le Framework, vous en trouverez beaucoup. Par exemple, System.Web.HttpContext.

Un type générique ne peut être instancié qu’avec des moyens C # (sans reflection) s’il a un constructeur par défaut. En outre, la contrainte de type générique new() doit être spécifiée:

 void Construct() where T : new() { var t = new T(); ... } 

L’appel de cette méthode en utilisant un type comme argument de type générique sans constructeur par défaut entraîne une erreur de compilation.