63 votes

Envoi de la référence de l'objet avant sa construction

J'ai vu le code suivant dans l'une de nos applications:

 public class First()
{
      private Second _second;

      public First()
      {
          _second = new Second(this);
          // Doing some other initialization stuff,
      }

}

public class Second
{
    public Second(First f)
    {
    }
}
 

Dans le constructeur First() , n’est-il pas mauvais que nous envoyions une référence de classe First() avant qu’elle soit entièrement construite? Je pense que l'objet n'est entièrement construit qu'une fois que la logique de contrôle a quitté le constructeur.

Ou est-ce que ça va?

70voto

Jon Skeet Points 692016

Ma question est, dans la Première() constructeur, n'est-il pas mauvais que nous envoyez une référence de classe Premier() AVANT qu'il est entièrement construit?

Un peu. Il peut être un problème, certainement.

Si l' Second constructeur juste détient une référence pour les utiliser plus tard, ce n'est pas trop mauvais. Si, d'autre part, l' Second constructeur appelle de nouveau en First:

public Second(First f)
{
    f.DoSomethingUsingState();
}

... et l'état n'a pas encore été fixés, alors ce serait une Très Mauvaise Chose. Si vous appelez un virtuel méthode sur First alors qu'il pourrait être pire, vous pourriez vous retrouver à l'appel du code qui n'a même pas eu une chance de s'exécuter tout de son corps du constructeur encore (bien que sa variable initialiseurs aura été exécutée).

En particulier, readonly des champs peut être vu avec une première valeur, puis plus tard avec une autre...

J'ai blogué sur ce il ya un moment, qui peut fournir de plus amples informations.

Bien sûr, sans faire ce genre de chose, il est assez difficile de créer deux mutuellement-référentiel des objets immuables...

17voto

Dan Bryant Points 19021

Si vous rencontrez ce modèle, vous pouvez vérifier si elle peut être remaniée en ceci à la place:

public class First()
{
      private Second _second;

      public First()
      {
          _second = new Second(this);
          // Doing some other initialization stuff,
      }

      private class Second
      {
          public Second(First f)
          {
          }
      }
}

Passage de la dépendance dans le constructeur implique une sorte de couplage entre les deux classes, la Première est de faire confiance que le Deuxième sait ce qu'il fait et de ne pas essayer de s'appuyer sur l'état non initialisé de la Première. Ce type de couplage fort est plus approprié quand la Seconde est un privé imbriquée sous-classe (et donc une mise en œuvre claire de détail) ou peut-être quand il est une classe interne.

11voto

Justin Niessner Points 144953

La réponse est, cela dépend. En règle générale, cependant, cela serait considéré comme une mauvaise idée en raison des conséquences potentielles.

Plus spécifiquement, cependant, tant que Second n'utilisera pas quoi que ce soit de First avant sa construction, tout devrait bien se passer. Si vous ne pouvez pas en garantir la qualité, vous pourriez certainement rencontrer des problèmes.

4voto

Virtlink Points 12475

Oui c'est un peu mauvais. Il est possible d'effectuer des opérations dans les champs First avant son initialisation complète, ce qui provoquerait un comportement indésirable ou indéfini.

La même chose se produit lorsque vous appelez une méthode virtuelle à partir de votre constructeur.

3voto

Anton Tykhyy Points 12680

En revanche, par exemple C++, CLR a pas de notion de entièrement construit ou incomplètement objets construits. Dès que l'allocateur de mémoire renvoie un objet de mise à zéro et avant l'exécution du constructeur, il est prêt à l'emploi (à partir du CLR de point de vue). Elle a son dernier type, les appels à des méthodes virtuelles invoquer la plupart des dérivés de remplacer etc. Vous pouvez utiliser this dans le corps du constructeur, l'appel des méthodes virtuelles etc. Cela peut en effet provoquer des problèmes avec l'ordre de l'initialisation, mais il n'y a rien dans le CLR pour les prévenir.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X