Je veux utiliser l'unité résout IService
à deux implémentations différentes, d'utiliser une classe wrapper, l'équivalent de:Résolution des classes wrapper en C# avec le conteneur Unité IoC
IService service = new DispatcherService(new RealService(), Application.Current.Dispatcher);
Lorsque les deux DispatcherService
et RealService
mettre en œuvre l'interface IService
.
J'ai une bibliothèque contenant certains services avec des opérations asynchrones. Une forme simplifiée de ce service ressemble à ceci:
public interface IService
{
IAsyncResult StartSomeOperation();
event EventHandler<EventArgs> SomeOperationCompleted;
}
J'ai implémentations pour tous ces services. Je souhaite que cette bibliothèque reste exempte de dépendances sur WPF et sur les conteneurs IoC, mais prête à être utilisée au mieux dans les cas où des conteneurs IoC et éventuellement WPF sont utilisés.
J'ai un WPi Ui utilisant le conteneur Unity IoC. Le code répétitif le plus courant concerne les gestionnaires terminés - ils doivent être ramenés sur le thread d'interface utilisateur à l'aide de Dispatcher. Donc, je pense à un emballage, comme ceci:
using System;
using System.Windows.Threading;
public class DispatcherService : IService
{
private Dispatcher dispatcher;
private IService wrappedService;
public DispatcherService(IService wrappedService, Dispatcher dispatcher)
{
this.wrappedService = wrappedService;
this.wrappedService.SomeOperationCompleted += this.OnWrappedOperationCompleted;
this.dispatcher = dispatcher;
}
public IAsyncResult StartSomeOperation()
{
return this.wrappedService.StartSomeOperation();
}
public event EventHandler<EventArgs> SomeOperationCompleted;
private void OnWrappedOperationCompleted(object sender, EventArgs e)
{
if (this.SomeOperationCompleted != null)
{
Action completedSynch =() => this.SomeOperationCompleted(sender, e);
this.dispatcher.Invoke(completedSynch);
}
}
}
Je new ceci avec code comme
IService service = new DispatcherService(new RealService(), Application.Current.Dispatcher);
Mais l'unité n'aime pas le fait que je compose deux implémentations différentes de la Interface IService. Ce code échoue horriblement:
UnityContainer container = new UnityContainer();
container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher);
container.RegisterType<IService, RealService>();
container.RegisterType<IService, DispatcherService>();
IService created = container.Resolve<IService>();
Et si j'inscrire les services dans l'autre ordre, le premier enregistrement est écrasé et je viens obtenir un RealService
.
Y a-t-il un moyen de contourner cela avec Unity? Ou cela a-t-il été fait avec l'AOP d'Unity? Et si c'est le cas, cela fonctionne-t-il dans Silverlight? Peut-il être fait sans utiliser Unity dans la bibliothèque d'origine du tout.
Je peux travailler autour d'une sous-classe d'interface « marqueur », à savoir
public interface IServiceWithDispatcher : IService
{
}
...
UnityContainer container = new UnityContainer();
container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher);
container.RegisterType<IService, RealService>();
container.RegisterType<IServiceWithDispatcher, DispatcherService>();
Mais je ne pense pas que ce soit une bonne idée, l'interface vide est laid et ce ne sera pas bien échelle .
Quelle est la manière de résoudre cet arbre d'objets?
Mise à jour:
Conformément à la réponse de Dzmitry Huba donnée, voici quelques exemples de code:
Ajouter une référence à Microsoft.Practices.Unity.StaticFactory
Code de travail simple:
UnityContainer container = new UnityContainer();
container.AddNewExtension<StaticFactoryExtension>()
.Configure<IStaticFactoryConfiguration>()
.RegisterFactory<IService>(cont =>
new DispatcherService(new RealService(), Application.Current.Dispatcher));
IService created = container.Resolve<IService>();
Plus de code de travail complet, qui traite mieux avec le p dépendances POTENTIELS le service réel, comme un conteneur IoC doit:
UnityContainer container = new UnityContainer();
container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher);
container.RegisterType<IService, RealService>("Real");
container.AddNewExtension<StaticFactoryExtension>()
.Configure<IStaticFactoryConfiguration>()
.RegisterFactory<IService>(cont =>
new DispatcherService(
cont.Resolve<IService>("Real"),
cont.Resolve<Dispatcher>()));
IService created = container.Resolve<IService>()
En outre, étant donné que l'enregistrement de l'usine est vraiment bavard, et je vais faire plus d'un d'entre eux, je fait une méthode d'extension:
public static class ContainerExtensions
{
public static void RegisterFactory<T>(this IUnityContainer container, FactoryDelegate factoryDelegate)
{
container.AddNewExtension<StaticFactoryExtension>()
.Configure<IStaticFactoryConfiguration>()
.RegisterFactory<T>(factoryDelegate);
}
}
Excellent, merci pour la suggestion d'usine statique. Vous devez ajouter une référence à Microsoft.Practices.Unity.StaticFactory. J'ai posté un exemple de code. – Anthony