Appelez un constructeur du corps d’un autre en C #

J’ai besoin d’appeler un constructeur du corps d’un autre. Comment puis je faire ça?

Fondamentalement

class foo { public foo (int x, int y) { } public foo (ssortingng s) { // ... do something // Call another constructor this (x, y); // Doesn't work foo (x, y); // neither } } 

Tu ne peux pas.

Vous devrez trouver un moyen d’enchaîner les constructeurs, comme dans:

 public foo (int x, int y) { } public foo (ssortingng s) : this(XFromSsortingng(s), YFromSsortingng(s)) { ... } 

ou déplacez votre code de construction dans une méthode d’installation commune, comme ceci:

 public foo (int x, int y) { Setup(x, y); } public foo (ssortingng s) { // do stuff int x = XFromSsortingng(s); int y = YFromSsortingng(s); Setup(x, y); } public void Setup(int x, int y) { ... } 

this(x, y) est correct, mais il doit l’être avant le début du corps du constructeur:

 public Foo(int x, int y) { ... } public Foo(ssortingng s) : this(5, 10) { } 

Notez que:

  • Vous pouvez uniquement chaîner un constructeur, soit this ci, soit la base – ce constructeur peut chaîner un autre, bien sûr.
  • Vous ne pouvez pas chaîner à un constructeur après avoir exécuté un code quelconque dans le corps du constructeur.
  • Vous ne pouvez pas utiliser this dans les arguments de l’autre constructeur, y compris en appelant des méthodes d’instance, mais vous pouvez appeler des méthodes statiques.
  • Tous les initialiseurs de variables d’instance sont exécutés avant l’appel chaîné.

J’ai un peu plus d’informations dans mon article sur l’enchaînement des constructeurs .

Pour appeler explicitement les constructeurs de base et de classe, vous devez utiliser la syntaxe donnée ci-dessous (notez que vous ne pouvez pas l’utiliser en C # pour initialiser des champs comme en C ++):

 class foo { public foo (int x, int y) { } public foo (ssortingng s) : this(5, 6) { // ... do something } } 

// EDIT: Notez que vous avez utilisé x, y dans votre échantillon. Bien sûr, les valeurs données lors de l’appel de ctor de cette manière ne peuvent pas s’appuyer sur les parameters d’un autre constructeur, elles doivent être résolues d’une autre manière (elles n’ont pas besoin d’être des constantes bien que dans l’exemple de code édité ci-dessus). Si x et y sont calculés à partir de s , vous pouvez le faire comme suit:

 public foo (ssortingng s): this (GetX (s), GetY (s))

Ceci n’est pas supporté – voir Constructeurs en C # .

Cependant, vous pouvez implémenter une méthode commune (privée) que vous appelez à partir des différents constructeurs …

J’ai rencontré ce problème une ou deux fois moi-même … J’ai fini par extraire la logique dont j’avais besoin dans cet autre constructeur en une méthode de private void et en l’appelant à ces deux endroits.

 class foo { private void Initialize(int x, int y) { //... do stuff } public foo(int x, int y) { Initialize(x, y); } public foo(ssortingng s_ { // ... do stuff Initialize(x, y) // ... more stuff } } 

Il y a une note dans la description de MethodBase.Invoke dans MSDN

Si cette surcharge de méthode est utilisée pour appeler un constructeur d’instance, l’object fourni pour obj est réinitialisé. c’est-à-dire que tous les initialiseurs d’instance sont exécutés. La valeur de retour est null. Si un constructeur de classe est appelé, la classe est réinitialisée. c’est-à-dire que tous les initialiseurs de classe sont exécutés. La valeur de retour est null.

Vous pouvez obtenir la méthode du constructeur par reflection et l’appeler via Invoke dans le corps de votre nouveau constructeur. Mais je ne l’ai pas essayé . Et, bien entendu, cette solution présente de nombreux inconvénients.