2010-08-04 4 views
4

J'ai une classe qui prend une interface en tant qu'argument de constructeur. Il y a deux implémentations de cette interface et je veux décider quelle implémentation utiliser lors de l'exécution en fonction d'une variable. Le problème est que la classe ci-dessus est profonde dans une hiérarchie d'objets qui est résolue par Autofac et donc je ne peux pas passer dans l'argument.Autofac - résoudre un composant avec des paramètres dynamiquement

Quelque chose comme ci-dessous est ce que j'essaie d'atteindre.

public interface IInterface1 {} 
public interface IInterface2 {} 

public class Class1 : IInterface2 
{ 
    public Class1(IInterface1 interface1) 
    { 
    } 
} 

public class Class2 
{ 
    public Class2(IInterface2 interface2) 
    { 
    } 
} 

public class Class3 
{ 
    public void GetClass2Instance(string interface1ImplementationToChoose) 
    { 
     // want to change which implementation of IInterface1 is resolved based on the interface1ImplementationToChoose variable 
     var class2 = container.Resolve<Class2>(); 
    } 
} 

Des idées?

MISE À JOUR:

Pour clarifier les choses, ceci est une hiérarchie d'objets existant qui est utilisé par les applications existantes qui fonctionnent bien. En outre, le modèle d'objet est beaucoup plus grand que celui montré dans cet exemple. Par conséquent, je ne veux pas vraiment avoir à transmettre une usine à chaque constructeur dans le graphe d'objets pour être utilisé par une classe en profondeur dans ce graphe.

Existe-t-il un moyen de faire passer une implémentation différente de IInterface1 dans Class1 sans que Class2 ne sache quoi que ce soit?

Merci

+0

Vous dites "il y a deux implémentations de cette interface .." mais votre exemple ne le montre pas très bien. Pourriez-vous élaborer, alors je mettrai à jour ma réponse en conséquence. –

Répondre

6

Oui, injecter une usine qui cache la façon dont les types sont choisis:

public class Class3 
{ 
    private Func<string, Class2> _class2Factory; 
    public Class3(Func<string, Class2> class2Factory) 
    { 
     _class2Factory = class2Factory; 
    } 

    public void GetClass2Instance(string interface1ImplementationToChoose) 
    { 
     var class2 = _class2Factory(interface1ImplementationToChoose); 
    } 
} 

Et puis la configuration du conteneur, quelque chose le long de ces lignes:

builder.RegisterType<Implementation1>().Named("imp1").As<IInterface1>(); 
builder.RegisterType<Implementation2>().Named("imp2").As<IInterface1>(); 
builder.Register<Func<string, Class2>>(c => 
    { 
     var context = c.Resolve<IComponentContext>(); 
     return imp => new Class2(context.Resolve<IInterface1>(imp)); 
    }); 
builder.RegisterType<Class3>(); 

Vous pouvez maintenant utiliser Class3 comme ceci:

public class Class4 
{ 
    public Class4(Class3 class3) 
    { 
     var class2with1 = class3.GetClass2Instance("imp1"); 
     var class2with2 = class3.GetClass2Instance("imp2"); 
    } 
} 

REMARQUE: J'ai supposé que vous vouliez dire que Class2 devrait être injecté avec différentes implémentations de la même interface IInterface1. Votre exemple est un peu déroutant puisque vous montrez deux classes qui implémentent des interfaces différentes.

+0

Ça a l'air bien; aussi, c => new Class2 (context.Resolve (imp)) est suffisant (vous n'avez pas besoin de résoudre explicitement IComponentContext à moins que vous ne gardiez une référence autour de vous.) –

+0

Je ne suis pas seulement en train d'ajouter 'Class2' , dans ce cas, je suis en train d'enregistrer un délégué 'Func ', qui devra avoir son propre contexte. Droite? –

+0

@Nicholas - J'ai oublié que je devrais spécifier le type de délégué pour l'appel de registre, peut-être que cela a plus de sens maintenant. Je suis toujours sous l'impression que je devrais résoudre un nouveau contexte pour "stocker" dans le lambda ... –

Questions connexes