Enregistrez-types génériques ouverts pour tous les types d'application une interface avec StructureMap
-
25-10-2019 - |
Question
Je veux enregistrer tous mes types d'application IManager
afin qu'ils puissent être utilisés comme type T
pour la classe Lazy<T>
générique.
Par exemple:
public TetraRadioPropertyUpdater(Lazy<IRadioManager> lazyRadioManager)
J'utilise un scanner auto fait parce que mes types de béton et les interfaces sont internes et à cet effet, je ne peux pas utiliser le haut dans StructureMap mécanisme de balayage.
Dans la première déclaration de la boucle enregistrer tous mes types de IManager
comme For<IRadioManager>().Singleton().Use<RadioManager>()
En plus, je veux qu'ils soient enregistrés afin qu'ils puissent être utilisés comme type générique pour Lazy<T>
comme For<Lazy<IRadioManager>().Use<Lazy<RadioManger>>()
InterfaceScanner<IManager> interfaceScanner = new InterfaceScanner<IManager>();
// managerMapping looks like:
// { IRadioManager, RadioManager }
// { ICallManager, CallManager }
// .. more manager interface to plugin type pairs
foreach (KeyValuePair<Type, Type> managerMapping in interfaceScanner.Process())
{
// the key is the plugin type, value is the concrete type
For(managerMapping.Key).Singleton().Use(managerMapping.Value);
// something like this.. ?
For(typeof(Lazy<>)).Singleton().Use(c => new Lazy(() => c.GetInstance(managerMapping.Value)));
}
Est-ce possible? Comment dois-je configurer pour StructureMap?
La solution
Mise à jour: StructureMap v3 implémente cette sortie de la boîte,
cette astuce n'est plus nécessaire.Vous pouvez enregistrer explicitement les classes comme ceci:
container = new Container(x =>
{
x.Scan(y =>
{
y.TheCallingAssembly();
y.WithDefaultConventions();
});
x.For<Lazy<IFoo>>().Use(y => new Lazy<IFoo>(y.GetInstance<Foo>));
x.For<Lazy<IBar>>().Use(y => new Lazy<IBar>(y.GetInstance<Bar>));
x.For<Lazy<IBaz>>().Use(y => new Lazy<IBaz>(y.GetInstance<Baz>));
});
Il serait plus agréable si cela était fait automatiquement, cependant. Idéalement, la syntaxe suivante serait bien.
x.For(typeof(Lazy<>)).Use(typeof(Lazy<>));
Malheureusement, lors de l'exécution, StructureMap tentera de trouver le constructeur « vorace » pour Lazy<T>
et Settle sur public Lazy(Func<T> valueFactory, bool isThreadSafe)
. Comme il ne sait pas quoi faire avec le paramètre isThreadSafe booléen. Il lancera une exception. Vous pouvez explicitement tell StructureMap valeur à utiliser comme celui-ci.
x.For(typeof(Lazy<>)).Use(typeof(Lazy<>))
.CtorDependency<bool>("isThreadSafe").Is(true);
Ce qui arrêtera les exceptions, et utiliser la valeur « true » pour le paramètre isThreadSafe. La documentation de Lazy indique que le mode de sécurité de fil du constructeur de Lazy(Func<T> valueFactory)
par défaut est LazyThreadSafetyMode.ExecutionAndPublication
, qui est aussi ce que vous obtenez en passant vrai dans le paramètre isThreadSafe du constructeur ci-dessus, donc nous allons obtenir le même comportement que si nous avons appelé le constructeur nous voulions réellement utiliser en premier lieu (par exemple Lazy(Func<T> valueFactory)
). Vous pouvez lire la classe Lazy plus en détail .
Je me rends compte que cela ne répond pas directement à votre question en ce qui concerne la classe du scanner personnalisé, mais il devrait vous donner un bon départ, je l'espère.