web-dev-qa-db-fra.com

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 (string s)
    {
        // ... do something

        // Call another constructor
        this (x, y); // Doesn't work
        foo (x, y); // neither
    }
}
49
tom

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) { ... }
68
ladenedge

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:

  • Vous ne pouvez chaîner que sur un seul constructeur, soit this, soit base; ce constructeur peut naturellement en chaîner un autre.
  • Le corps du constructeur exécute after l'appel du constructeur en chaîne. Il n’existe aucun moyen d’exécuter d’abord le corps du constructeur. 
  • Vous ne pouvez pas utiliser 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.
  • Tous les initialiseurs de variable 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 .

34
Jon Skeet

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)) 
6
Marcin Deptuła

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 ...

1
Yahia

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
  }
}
1
DMac the Destroyer

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.

0
Кое Кто