web-dev-qa-db-fra.com

Comment résoudre une référence circulaire?

Comment résolvez-vous les problèmes de références circulaires comme la classe A a la classe B parmi ses propriétés, alors que la classe B a la classe A parmi ses propriétés?

Comment faire architecte pour ce genre de problèmes?

Si vous prenez un exemple de NHibernate, il existera une relation parent-enfant entre les objets.

Comment est-il capable de gérer ces scénarios parent-enfant?

18
user145610

Dans la plupart des cas, lorsque j'ai dû faire référence à deux éléments, j'ai créé une interface pour supprimer la référence circulaire. Par exemple:

AVANT

public class Foo
{
    Bar myBar;
}

public class Bar
{
    Foo myFoo;
}

Graphique de dépendance:

Foo     Bar
 ^       ^
 |       |
Bar     Foo

Foo dépend de Bar, mais Bar dépend aussi de Foo. S'ils se trouvent dans des assemblages distincts, vous aurez des problèmes de construction, en particulier si vous effectuez une reconstruction propre.

APRÈS

public interface IBar
{
}

public class Foo
{
    IBar myBar;
}

public class Bar : IBar
{
    Foo myFoo;
}

Graphique de dépendance:

Foo, IBar     IBar
    ^          ^
    |          |
   Bar        Foo

Foo et Bar dépendent tous deux de IBar. Il n'y a pas de dépendance circulaire, et si IBar est placé dans sa propre assemblée, Foo et Bar étant dans des assemblées séparées ne seront plus un problème.

26
Ed Bayiates

Je dirais à votre ami qu'il doit repenser son design. Les références circulaires que vous décrivez sont souvent une odeur de code qui présente un défaut de conception.

6
John Kraft

Contrairement à C++ (par exemple), C # n'a pas besoin de déclarations en aval pour résoudre les références circulaires. Par conséquent:

public class A
{
    public B B { get;set; }
}

public class B
{
    public A A { get;set; }
}

Cependant, ceci est souvent un indicateur de décisions de conception douteuses.

5
Anton Gogolev

Dans la plupart des cas, la meilleure solution consiste à modifier votre conception et à éviter une dépendance circulaire. Par exemple, vous pouvez effectuer l’une des opérations suivantes:

  1. Déplacez le code référencé commun vers un projet d'utilitaire dans votre solution et demandez aux autres projets de référencer le projet d'utilitaire
  2. Utilisez une interface comme expliqué par "Ed Bayiates" dans sa réponse. 
  3. S'il s'agit d'une petite quantité de code simple/commun, réécrivez-le pour l'une des classes afin de ne pas avoir à le référencer dans une dépendance circulaire. (Celui que j'apprécie moins)

Toutefois, si vous travaillez dans une solution comportant de nombreux projets et que vous ne pouvez pas apporter l’une des modifications ci-dessus, car vous ne possédez pas le code, il est trop difficile à implémenter, ou ne vaut pas la peine d’être corrigé, alors vous pouvez utiliser cette méthode:

Cliquez avec le bouton droit sur les références du projet et sélectionnez "Ajouter une référence ...". Puis, dans la fenêtre de dialogue qui apparaît, passez à l'onglet "Parcourir" et au bouton "Parcourir". À partir de là, vous pouvez rechercher le DLL et le sélectionner. C'est au mieux une solution de contournement qui peut poser des problèmes de génération, en particulier si les deux DLL sont mises à jour fréquemment et/ou comportent de nombreuses dépendances. Je ne recommande pas cette méthode, mais cela fonctionne à la rigueur.

Fissh

1
gadildafissh

cependant, si vous cherchez une solution plus rapide que de refaire l'architecture de nombreuses choses, essayez de construire une bibliothèque de classes dll contenant toutes les structures de données de votre projet principal contenant votre interface utilisateur qui a besoin de ces données, puis des autres dll que vous voulez à ajouter peut accéder à cette dll de structures de données afin de disposer de toutes les informations dont ils ont besoin pour s'exécuter mais peuvent tout de même être séparés - c'est ce qu'on appelle le modèle de conception à trois forces -

0
enf folife