8

J'ai le type de dépendance circulaire le plus simple dans structuremap - la classe A s'appuie sur la classe B dans son constructeur, et la classe B repose sur la classe A dans son constructeur. Pour casser la dépendance, j'ai fait que la classe B prenne la classe A comme une propriété, plutôt que comme un argument constructeur, mais structuremap se plaint encore.Dépendances circulaires dans StructureMap - peuvent-elles être rompues avec l'injection de propriété?

J'ai vu des dépendances circulaires cassées en utilisant cette méthode dans d'autres frameworks DI - est-ce un problème avec Structuremap ou est-ce que je fais quelque chose de mal?

Edit: Je dois mentionner que la propriété de la classe B est un tableau d'instances de classe A, câblé comme ceci:

x.For<IB>().Singleton().Use<B>().Setter(y => y.ArrayOfA).IsTheDefault(); 

Juste pour clarifier les choses, je veux la séquence suivante d'événements se produire:

  • construire une instance de b, "b"
  • construire une instance de a, "a", l'injection "b" dans son constructeur
  • Set "b.ArrayOfA" à [ "a"]

Et je veux que tout cela se produise en utilisant autowiring, si possible ...

Edit 2: Voici un exemple simplifié que les utilisations câblage explicite jusqu'à:

interface ILoader { } 
interface ILoaderManager { } 

class Loader : ILoader 
{ 
    public Loader(ILoaderManager lm) { } 
} 
class LoaderManager : ILoaderManager 
{ 
    public ILoader Loader { get; set; } // Was an array, but same circular dependency appears here 
} 

ObjectFactory.Configure 
(
    x => 
    { 
     x.For<ILoader>.Singleton().Use<Loader>(); 
     x.For<ILoaderManager>().Singleton().Use<LoaderManager>().OnCreation((c, a) => a.Loader = c.GetInstance<ILoader>()); 
    } 
); 

les causes de validation de configuration "dépendance bidirectionnelle problème détecté avec RequestedType: IocTest2.ILoader ..."

Répondre

3

Le plus proche que vous pouvez obtenir est quelque chose comme ceci:

x.For<IB>().Use<B>() 
    .OnCreation((ctx, instance) => 
    { 
     instance.ArrayOfA = new IA[] {new A(instance) }; 
    }); 

Si A a d'autres dépendances que vous souhaitez résoudre à partir du conteneur, vous pouvez les récupérer à partir de ctx dans le lambda OnCreation. StructureMap peut gérer la situation bidirectionnelle avec une solution de contournement en utilisant la résolution Lazy.

+0

Salut Joshua - Je viens d'essayer et j'ai un "problème de dépendance bidirectionnel" - Je pense que c'est un signe d'une dépendance circulaire dans StructureMap? La construction et la configuration d'un objet par StructureMap sont-elles réellement atomiques, de sorte que les références circulaires ne peuvent pas être résolues? Cela semble peu probable, mais je n'ai pas réussi à le faire fonctionner jusqu'à présent ... – Andy

+0

Le problème de dépendance bidirectionnelle indique une référence circulaire. Toutefois, l'exemple de code fourni par I fonctionnera car l'instance de B est créée avant l'appel de OnCreation lambda. Vous pouvez ensuite passer cette instance de B dans le constructeur de A, puis définir la propriété de B sur A. J'ai testé le code ci-dessus et cela fonctionne. Si vous rencontrez toujours des problèmes de référence circulaire, il doit y avoir d'autres dépendances que vous n'avez pas mentionnées. –

+0

Je dois préciser que lorsque vous utilisez mon exemple de code, vous ne devez PAS définir de politique pour que StructureMap effectue l'injection de setter sur B. Vous effectuez manuellement l'injection de setter dans le lambda OnCreation. –

0

StructureMap exécute vraisemblablement Setter Injection où il remplira les propriétés définissables publiques sur un objet qu'il résout. Selon la documentation,

Par défaut, tous les « Setters » publics sont facultatifs, ce qui signifie que ces setters ne seront définies que si elles sont explicitement configurés pour une instance spécifique

Alors avez-vous par hasard configurer les propriétés à câbler automatiquement? Si c'est le cas, vous aurez toujours le problème de dépendance circulaire.

Modifier: Je vois que vous avez. Dans votre exemple parce que B a un [] injecté, StructureMap doit résoudre la dépendance de chaque A pour B qui a besoin d'un [], et ainsi de suite ...

+0

IIRC, j'ai essayé la même chose dans le château de Windsor. Il a fait la résolution de la propriété après la résolution des constructeurs de composants, ce qui signifiait que la dépendance circulaire était effectivement rompue. En supposant que je ne rêvais pas de ce fait, je me demandais si StructureMap avait une facilité similaire? – Andy

+0

Voici un exemple de solutions de dépendance circulaire avec Windsor et StructureMap ici: http://bit.ly/aZsr9c. Je sais que c'est un peu plus vieux mais peut encore s'appliquer. Je remarque qu'il a utilisé 'TheInstanceNamed (" Processor1 ")' pour la dernière configuration de SetterDependency, peut-être que cela aidera? – statenjason

+0

Salut statenjason, merci beaucoup pour votre aide et le lien. Je l'ai essayé et j'ai toujours la dépendance circulaire. J'ai modifié ma question avec un petit fragment de code pour illustrer le problème. – Andy

5

Si vous avez une situation simple comme ClassA qui dépend de ClassB et ClassB qui dépend de ClassA, alors vous pouvez choisir l'un d'entre eux et convertir la dépendance en tant que dépendance paresseux. De cette façon, a travaillé pour moi et que l'erreur ne reparut plus ..

public class ClassA 
{ 
    private readonly Lazy<IClassB> _classB; 

    public Thing1(Lazy<IClassB> classB) 
    { 
     _classB = classB; 
    } 

    public IClassB ClassB => _classB.Value; 
} 

public class ClassB 
{ 
    public IClassA _classA { get; set; } 

    public ClassB (IClassA classA) 
    { 
     _classA = classA; 
    } 
} 

Plus d'infos ici: http://structuremap.github.io/the-container/lazy-resolution/

+0

C'est ** beaucoup ** mieux que la réponse acceptée. –