J'utilise le conteneur IOC UNITY, et je dois intercepter les appels pour résoudre pour une certaine interface de base et exécuter mon propre code personnalisé pour construire ces types.
En d'autres termes, dans le code d'échantillon ci-dessous, lorsque j'appelle Le conteneur d'unité standard n'est pas en mesure de construire ces objets ( Je suppose que je peux créer une extension de l'unité pour le faire, mais je Je me demandais s'il y a déjà une solution là-bas, je peux emprunter. p> p> conteneur.Resolve
MyFactoryFunction Code> Pour en construire un, sinon je veux qu'il retourne la copie en cache. p>
4 Réponses :
Le conteneur Unity agit déjà comme une usine qui sait construire (et effectuer une injection de dépendance pour) des types arbitraires, de sorte que votre usine accepte un type T semble redondante. Pouvez-vous élaborer plus sur pourquoi cela n'est pas possible? P>
Si cela n'est vraiment pas possible (plus probablement trop de travail), vous pouvez peut-être enregistrer votre usine avec le conteneur à la place? P>
La raison est que nous utilisons .NET Remoting pour créer la classe. Nous ne pouvons donc pas simplement appeler son constructeur - le type de béton n'existe dans aucun assemblage sur le client. Nous devons nous connecter à un serveur et demander son objet qui remplit l'interface en question.
OK, j'ai mis en œuvre l'extension moi-même. Dans le constructeur, je cache l'objet car je veux que ce soit un singleton w.r.t mon conteneur. La raison de
basecontext code> est que je veux que cela soit mis en cache dans le conteneur de niveau supérieur plutôt que dans des conteneurs enfants à partir desquels il a été demandé. P>
MyFactory factory = new MyFactory();
container = new UnityContainer();
container.AddExtension(new FactoryMethodUnityExtension<IBase>(factory.Create));
Pourriez-vous expliquer votre stratégie de cache? Pourquoi avoir besoin d'ajouter du type créé au conteneur après la création?
@Dmitriy - parce que je veux seulement créer chaque interface de télécommande .NET une fois
En complétude, je devrais ajouter une autre réponse qui fonctionne sous l'unité 2, puisque mon autre réponse ne fonctionne plus. Il est légèrement plus impliqué puisque vous devez faire une politique de constructeur personnalisée. Grâce à CTavares du projet Unity qui a fourni beaucoup d'aide sur ce fil dans la mise en œuvre de cette optique:
public class FactoryUnityExtension : UnityContainerExtension { private ICustomFactory factory; private CustomFactoryBuildStrategy strategy; public FactoryUnityExtension(ICustomFactory factory) { this.factory = factory; } protected override void Initialize() { this.strategy = new CustomFactoryBuildStrategy(factory, Context); Context.Strategies.Add(strategy, UnityBuildStage.PreCreation); Context.Policies.Set<ParentMarkerPolicy>(new ParentMarkerPolicy(Context.Lifetime), new NamedTypeBuildKey<ParentMarkerPolicy>()); } } public class ParentMarkerPolicy : IBuilderPolicy { private ILifetimeContainer lifetime; public ParentMarkerPolicy(ILifetimeContainer lifetime) { this.lifetime = lifetime; } public void AddToLifetime(object o) { lifetime.Add(o); } } public interface ICustomFactory { object Create(Type t); bool CanCreate(Type t); } public class CustomFactoryBuildStrategy : BuilderStrategy { private ExtensionContext baseContext; private ICustomFactory factory; public CustomFactoryBuildStrategy(ICustomFactory factory, ExtensionContext baseContext) { this.factory = factory; this.baseContext = baseContext; } public override void PreBuildUp(IBuilderContext context) { var key = (NamedTypeBuildKey)context.OriginalBuildKey; if (factory.CanCreate(key.Type) && context.Existing == null) { context.Existing = factory.Create(key.Type); var ltm = new ContainerControlledLifetimeManager(); ltm.SetValue(context.Existing); // Find the container to add this to IPolicyList parentPolicies; var parentMarker = context.Policies.Get<ParentMarkerPolicy>(new NamedTypeBuildKey<ParentMarkerPolicy>(), out parentPolicies); // TODO: add error check - if policy is missing, extension is misconfigured // Add lifetime manager to container parentPolicies.Set<ILifetimePolicy>(ltm, new NamedTypeBuildKey(key.Type)); // And add to LifetimeContainer so it gets disposed parentMarker.AddToLifetime(ltm); // Short circuit the rest of the chain, object's already created context.BuildComplete = true; } } }
Unity (v2) vous permet de spécifier une usine. Il permet de faire quelques fonctions différentes, notamment de prendre le type à accumuler / nom, etc. Exemple simple:
cont.RegisterType<TestClass>(new InjectionFactory(c => CreateTest())); var svc = cont.Resolve<TestClass>();
On dirait que vous devez utiliser la forme générique de registertype