Factory 和 IOC 在一起 - 如何同时使用两者?

Factory and IOC together - how to use then both?

所以我有这个应用程序,我在其中使用 IOC (autofac)。与此同时,我发现自己处于需要工厂的位置。在工厂内部,我创建了具有依赖关系的新对象 - 所以现在我想知道,我怎么能把它们结合起来呢?

public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory
{
    public ISubscriptionHandler GetProvider(StreamType streamType)
    {
        switch (streamType)
        {
            case StreamType.Rss:
                return new RssSubscriptionHandler(null,null,null,null);
            case StreamType.Person:
                return new PersonSubscriptionHandler(null, null, null, null);
            default:
                throw new ArgumentOutOfRangeException(nameof(streamType), streamType, null);
        }
    }
}

你不能使用 IoC 永远抽象掉对象的实例化。在某些时候,您将不得不创建一个具体实例(在您的工厂或 IoC 容器内)

您可以将您的 autofac 容器注入您的工厂,或者,由于您的工厂本身实现了一个接口,那么您可以将不同版本的工厂注入到 class 可能需要的地方(例如,如果您需要一个用于单元测试目的的不同工厂)

我解决了。有点儿。因为我不想依赖 Autofac it self 我被撕裂了。但多亏了@martin-costello,我才意识到也许我不需要使用 autofac,而是在 IDependencyResolver 中构建,它不那么邪恶。由于我无法将 autofac 注册为 IDependencyResolver,因此我将 DependencyResolver 注册为 IDependencyResolver。又近了一步。由于注册发生在 autofac DependencyResolver.SetResolver 发生之前,我需要使用 Lazy,它最终解决了我的问题。

这是代码(或者至少是我发现的最佳解决方案)

// other registration
builder.RegisterType<RssSubscriptionHandler>();
builder.RegisterType<PersonSubscriptionHandler>();
// even more registration here

builder.RegisterType<SubscriptionHandlerFactory>()
       .As<ISubscriptionHandlerFactory>()
       .WithParameter(new TypedParameter(typeof(Lazy<IDependencyResolver>), 
                      new Lazy<IDependencyResolver>(() => DependencyResolver.Current)));

然后工厂对此进行更改(清理之前):

public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory
{
    private readonly Lazy<IDependencyResolver> resolver;

    public SubscriptionHandlerFactory(Lazy<IDependencyResolver> resolver)
    {
        this.resolver = resolver;
    }

    public ISubscriptionHandler GetProvider(StreamType streamType)
    {
        switch (streamType)
        {
            case StreamType.Rss:
                return (ISubscriptionHandler)this.resolver.Value.GetService(typeof(RssSubscriptionHandler));
            case StreamType.Person:
                return (ISubscriptionHandler)this.resolver.Value.GetService(typeof(PersonSubscriptionHandler));
            default:
                throw new ArgumentOutOfRangeException(nameof(streamType), streamType, null);
        }
    }
}

目前这是我能够找出的 best/clean/less evil/less specific/abstract/whatever 解决方案。欢迎任何评论。

您可以使用 named and keyed service 并使用 IIndex<TKey, TService>

检索实例

注册可能如下所示:

builder.RegisterType<RssHandler>().Keyed<ISubscriptionHandler>(StreamType.Rss);
builder.RegisterType<PersonHandler>().Keyed<ISubscriptionHandler>(StreamType.Person);
builder.RegisterType<SubscriptionHandlerFactory>().As<ISubscriptionHandlerFactory>();

和这样的工厂:

public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory
{
    public SubscriptionHandlerFactory(IIndex<StreamType, ISubscriptionHandler> handlers)
    {
        this._handlers = handlers;
    }

    private readonly IIndex<StreamType, ISubscriptionHandler> _handlers;

    public ISubscriptionHandler GetProvider(StreamType streamType)
    {
        return this._handlers[streamType];
    }
}