使用Unity IoC容器解析C#中的包装器类 [英] Resolving wrapper classes in C# with the Unity IoC container

查看:140
本文介绍了使用Unity IoC容器解析C#中的包装器类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Unity resolve IService到两个不同的实现,以利用包装类,等效于:

I want to use Unity resolve IService to two different implementations, to make use of a wrapper class, the equivalent of:

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

DispatcherServiceRealService都实现IService接口的地方.

Where both DispatcherService and RealService implement the IService interface.

我有一个包含一些带有异步操作的服务的库.此服务的简化形式如下:

I have a library containing some services with asynchronous operations. A simplified form of this service looks like this:

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

我有所有这些服务的实现.我希望该库保持对WPF和IoC容器的依赖性,但准备好在使用IoC容器以及可能使用WPF的情况下最佳使用.

I have implementations for all of these services. I want this library to remain free of dependencies on WPF and on IoC containers, but ready for best use in cases where IoC containers and possibly WPF are in use.

我有一个使用Unity IoC容器的WPF Ui.最常见的重复代码是围绕已完成的处理程序-需要使用分派器将它们编组回UI线程.所以我在考虑一个包装器,像这样:

I have a WPF Ui using the Unity IoC container. The most common repetitive code is around the completed handlers - they need to be marshalled back onto the UI thread using the Dispatcher. So I'm thinking about a wrapper, like this:

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

但是统一并不喜欢我正在组成IService接口的两个不同实现的事实. 这段代码严重失败:

But unity does not like the fact that I am composing two different implementations of the IService interface. This code fails horribly:

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

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

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

And if I register the services in the other order, the first registration is overwritten and I just get a RealService.

Unity是否可以解决此问题?还是使用Unity的AOP完成了此操作?如果是的话,那在Silverlight中行得通吗?完全不用原始库中的Unity就能做到.

Is there a way around this with Unity? Or has this been done with Unity's AOP? And if so, does that work in Silverlight? Can it be done without using Unity in the original library at all.

我可以解决标记"问题,接口子类,即

I can work around with a "marker" interface subclass, i.e.

public interface IServiceWithDispatcher : IService
{
    
}

...

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

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

但是我不认为这是一个好主意,空接口很丑陋,扩展性也不太好.

But I don't think that this is such a good idea, the empty interface is ugly and this won't scale well.

解决该对象树的方法是什么?

What's the way to resolve this object tree?

与Dzmitry Huba给出的答案一致,这是一些示例代码:

In line with Dzmitry Huba's the answer given, here is some sample code:

添加对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容器应:

More complete working code, that deals better with the potential dependencies the real service, like an IoC container should:

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

此外,考虑到工厂注册确实很冗长,并且我将做很多工作,所以我做了一个扩展方法:

Also, considering that the factory registration is really verbose, and I will be doing more than one of them, I made an extension method:

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

推荐答案

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

You can use RegisterType overloads that accept string based names. In this case you'll do something like:

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

并使用名称声明您的依赖关系.

and announce your dependencies with names as well.

[Dependency("real")]

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

This will allow you to avoid marker interface which is in most cases is not a good idea.

但是,如果要保持代码在Unity中的存在(如DependencyAttribute),并且在大多数情况下,在应用程序生命周期内仅使用一种实现(例如,仅使用DispatcherService),您基本上可以决定是否需要是否用DispatcherService包装请求的IService.在这种情况下,您可以查看静态工厂扩展团结.工厂代表将了解配置,并且基于配置的情况是将IService与DispatcherService包装在一起,或者仅返回从容器获取的IService实现.

However if want to keep your code clean from Unity presence (like DependencyAttribute) and in most cases you will use only 1 implementation during application lifetime (for example, only DispatcherService will be used) you basically to make decision whether you need to wrap requested IService with DispatcherService or not. In this case you can look at Static Factory Extension for Unity. Factory delegate will be aware of configuration and based on configuration will either wrap IService with DispatcherService or simply return IService implementation obtained from container.

这篇关于使用Unity IoC容器解析C#中的包装器类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆