c# - 使用 Unity IoC 容器解析 C# 中的包装类

标签 c# unity-container ioc-container wrapper

我想使用Unity解析IService到两个不同的实现,以使用包装类,相当于:

 IService service = new DispatcherService(new RealService(), Application.Current.Dispatcher);

其中 DispatcherServiceRealService 都实现 IService 接口(interface)。

我有一个库,其中包含一些具有异步操作的服务。该服务的简化形式如下所示:

public interface IService
{
    IAsyncResult StartSomeOperation();
    event EventHandler<EventArgs> SomeOperationCompleted;
}

我已经实现了所有这些服务。我希望这个库不依赖于 WPF 和 IoC 容器,但可以在使用 IoC 容器和可能的 WPF 的情况下实现最佳使用。

我有一个使用 Unity IoC 容器的 WPF Ui。最常见的重复代码是围绕已完成的处理程序 - 需要使用 Dispatcher 将它们编码回 UI 线程。所以我正在考虑一个包装器,如下所示:

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);
        }
    }
}

我可以用类似的代码来更新它

IService service = new DispatcherService(new RealService(), Application.Current.Dispatcher);

但是 Unity 不喜欢我编写 IService 接口(interface)的两个不同实现。 这段代码严重失败:

    UnityContainer container = new UnityContainer();
    container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher);
    container.RegisterType<IService, RealService>();
    container.RegisterType<IService, DispatcherService>();

    IService created = container.Resolve<IService>();

如果我以其他顺序注册服务,第一个注册将被覆盖,我只会得到一个 RealService

Unity 有办法解决这个问题吗?或者这是用Unity的AOP完成的?如果是这样,这在 Silverlight 中有效吗?能不能完全不使用原库中的Unity来完成。

我可以使用“标记”接口(interface)子类,即

public interface IServiceWithDispatcher : IService
{
    
}

...

UnityContainer container = new UnityContainer();
container.RegisterInstance<Dispatcher>(Application.Current.Dispatcher);

container.RegisterType<IService, RealService>();
container.RegisterType<IServiceWithDispatcher, DispatcherService>();

但我不认为这是一个好主意,空的界面很难看,而且扩展性不好。

如何解析这个对象树?

<小时/>

更新:

根据 Dzmitry Huba 给出的答案,这里是一些示例代码:

添加对 Microsoft.Practices.Unity.StaticFactory 的引用

简单的工作代码:

    UnityContainer container = new UnityContainer();

    container.AddNewExtension<StaticFactoryExtension>()
        .Configure<IStaticFactoryConfiguration>()
        .RegisterFactory<IService>(cont =>
                new DispatcherService(new RealService(), Application.Current.Dispatcher));
        
    IService created = container.Resolve<IService>();

更完整的工作代码,可以更好地处理实际服务的潜在依赖关系,就像 IoC 容器应该的那样:

    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>()

另外,考虑到工厂注册确实很冗长,而且我会做不止一个,所以我做了一个扩展方法:

public static class ContainerExtensions
{
    public static void RegisterFactory<T>(this IUnityContainer container, FactoryDelegate factoryDelegate)
    {
        container.AddNewExtension<StaticFactoryExtension>()
            .Configure<IStaticFactoryConfiguration>()
            .RegisterFactory<T>(factoryDelegate);
    }
}

最佳答案

您可以使用接受基于字符串的名称的 RegisterType 重载。在这种情况下,您将执行以下操作:

container.RegisterType<IService, RealService>("real");
container.RegisterType<IService, DispatcherService>("dispatcher");

并用名称声明您的依赖项。

[Dependency("real")]

这将使您避免标记界面,这在大多数情况下不是一个好主意。

但是,如果想要保持代码不受 Unity 影响(例如 DependencyAttribute),并且在大多数情况下,您将在应用程序生命周期内仅使用 1 个实现(例如,仅使用 DispatcherService),那么您基本上需要决定是否需要是否使用 DispatcherService 包装请求的 IService。在这种情况下,您可以查看 Static Factory Extension for Unity 。工厂委托(delegate)将了解配置,并根据配置使用 DispatcherService 包装 IService 或简单地返回从容器获取的 IService 实现。

关于c# - 使用 Unity IoC 容器解析 C# 中的包装类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1989299/

相关文章:

javascript - GridPanel CheckboxSelectionModel - 所选总和

c# - 将用户生成的查询向下传递到 n 层应用程序

c# - html-元素属性,自定义HtmlHelper.xxxxFor

asp.net-mvc - PerRequestLifetimeManager 和 Task.Factory.StartNew - 使用 Unity 进行依赖注入(inject)

c# - 如何使用 IoC 注入(inject)打开的连接

c# quartz.net 一项大工作或小多项工作

.net - Unity IOC 最后更新于 2015 年 10 月。他们停止进一步开发了吗?

c# - 如何在 Unity 中使用 Serilog?

dependency-injection - 什么时候使用属性注入(inject)?

dependency-injection - 谁创造了 "Inversion of Control Container"这个术语,哪个公共(public)容器最先出现?