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 (string 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 (string s) : this(XFromString(s), YFromString(s)) { ... }
ou déplacez votre code de construction dans une méthode d'installation courante, comme ceci:
public foo (int x, int y) { Setup(x, y); }
public foo (string s)
{
// do stuff
int x = XFromString(s);
int y = YFromString(s);
Setup(x, y);
}
public void Setup(int x, int y) { ... }
this(x, y)
a raison, mais cela doit être avant le début du corps du constructeur:
public Foo(int x, int y)
{
...
}
public Foo(string s) : this(5, 10)
{
}
Notez que:
this
, soit base
; ce constructeur peut naturellement en chaîner un autre.this
dans les arguments de l'autre constructeur, y compris les méthodes d'instance d'appel, mais vous can appelez des méthodes statiques.J'ai un peu plus d'informations dans mon article sur l'enchaînement des constructeurs .
Pour appeler explicitement à la fois le constructeur de base et le constructeur de classe, vous devez utiliser la syntaxe donnée ci-dessous (remarquez 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 (string 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 dépendre des paramètres 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 modifié ci-dessus). Si x
et y
sont calculés à partir de s
, vous pouvez le faire comme suit:
public foo (string 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 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 dans une méthode private void
et en l'appelant aux deux endroits.
class foo
{
private void Initialize(int x, int y)
{
//... do stuff
}
public foo(int x, int y)
{
Initialize(x, y);
}
public foo(string s_
{
// ... do stuff
Initialize(x, y)
// ... more stuff
}
}
Il y a une note dans description sur MethodBase.Invoke
dans MSDN
Si cette surcharge de méthode est utilisée pour appeler un constructeur d'instance, le fichier l'objet fourni pour obj est réinitialisé; c'est-à-dire toute instance les initialiseurs sont exécutés. La valeur de retour est null. Si une classe constructeur est appelé, la classe est réinitialisée; c'est-à-dire toute classe les initialiseurs sont exécutés. La valeur de retour est null.
C'est à dire. vous pouvez obtenir la méthode du constructeur par réflexion et l'appeler via Invoke
dans le corps de votre nouveau constructeur. Mais je ne l'ai pas essayé. Et, bien sûr, cette solution présente de nombreux inconvénients.