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é à obtenir des éclaircissements à ce sujet par des experts.
N'oubliez pas que si vous ne fournissez pas de 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 qui reposait sur la présence d'un constructeur par défaut, Foo f = new Foo();
, ce code serait maintenant rompu.
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
qui explicite le fait que vous empêchez la construction d'instances sans données d'entrée.
Cependant, il est parfois nécessaire de fournir un constructeur par défaut (qu'il soit 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 cas où une classe a plusieurs constructeurs paramétrés mais requiert é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 Empty
statique serait plus facilement identifiable.
Je dirais non , certainement pas toujours. Supposons que vous ayez une classe avec des champs en lecture seule qui doivent être initialisés à une valeur quelconque et qu'il n'y a pas de valeur par défaut raisonnable (ou que vous ne voulez pas qu'il en soit ainsi) 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 une bonne idée que s’il est logique d’avoir un tel objet.
Si vous produisez un objet qui n'est pas dans un état valide à partir d'un tel constructeur, la seule chose à faire est d'introduire un bug.
Oui Il est préférable de disposer d'un constructeur par défaut afin d'éviter toute confusion. J'ai vu des gens ne rien faire à l'intérieur d'un constructeur par défaut (même dans les propres classes de Microsoft), mais je souhaite tout de même le conserver car les objets reçoivent automatiquement le type (type) par défaut. Les classes qui ne spécifient pas le constructeur par défaut, .NET les ajoutera automatiquement pour vous.
La sérialisation a besoin Constructeur par défaut si vous utilisez des sérialiseurs existants comme il convient pour les sérialiseurs à usage général, sinon vous devez créer votre propre implémentation.
En remarque, lorsque vous utilisez struct au lieu de classe, notez qu'il est impossible de laisser le constructeur par défaut non plus, et qu'il n'est pas possible de le définir vous-même. L'état par défaut de la structure (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) n'interrompra pas l'implémentation de la structure.
Dans la plupart des cas, un constructeur par défaut est une bonne idée. Mais puisque vous utilisez le mot "toujours", il suffit d'un contre-exemple. Si vous regardez le cadre, vous en trouverez beaucoup. Par exemple, System.Web.HttpContext.
Un type générique ne peut être instancié avec des moyens C # (sans réflexion) que s'il a un constructeur par défaut. De plus, la contrainte de type générique new()
doit être spécifiée:
void Construct<T>()
where T : new()
{
var t = new T();
...
}
L'appel de cette méthode en utilisant un type en tant qu'argument de type générique sans constructeur par défaut entraîne une erreur de compilation.