autofac工厂模式

时间:2017-11-17 17:32:12

标签: c# dependency-injection inversion-of-control autofac

我想在Autofac中实现工厂模式。这是在Ninject中完成的:

Bind<ICarFilter>().To<CarFilter >();
Bind<IBikeFilter>().To<BikeFilter>();
Bind<IFilterFacade>().ToFactory().InSingletonScope();

这是IFilterFacade的定义

public interface IFilterFacade
    {    
        ICarFilter CreateCarFilter();

        IBikeFIlter CreateBikeFilter();         
    }

如果我想要一个CarFilter类型的实例,我需要做的就是:

public class HomeController(IFilterFacade filterFacade)
{
    FilterFacade = filterFacade;
}

public IFilterFacade FilterFacade { get;set; }

public ActionResult Index()
{
  var bikeFilter = FilterFacade.CreateBikeFilter();
}

如何在AutoFac中执行此操作的任何示例。我检查了AutoFac文档,但无法找到答案或示例。

3 个答案:

答案 0 :(得分:1)

Autofac 中没有等效的ToFactory,但您可以轻松实现等效的通用工厂。

public interface IFilterFactory
{
    TFilter Get() where TFilter : IFilter; 
}

public class FilterFactory : IFilterFactory
{

    public FilterFactory(ILifetimeScope scope)
    {
        this._scope = scope; 
    }

    private readonly ILifetimeScope _scope; 

    public TFilter Get<TFilter>()
    {
        return this._scope.Resolve<TFilter>(); 
    }
}

然后像这样注册:

builder.RegisterType<FilterFactory>().As<IFilterFactory>(); 
builder.RegisterType<BikeFilter>().As<IBikeFilter>(); 
builder.RegisterType<CarFilter>().As<ICarFilter>(); 

并以这种方式使用

public class HomeController
{ 
    private readonly IFilterFactory _filters;

    public HomeController(IFilterFactory filters)
    {
        this._filters = filters; 
    }

    public ActionResult Index()
    {
        var bikeFilter = this._filters.Get<IBikeFilter>();
        // ...
    }
}

我将Create方法重命名为Get,因为该方法将在生命周期范围内查找实例,并仅在需要时创建一个实例。

另一种可能的解决方案可能是使用Named and Keyed Service和内置IIndex类型。

builder.RegisterType<BikeFilter>().Named<IFilter>("Bike"); 
builder.RegisterType<CarFilter>().Named<IFilter>("Car");

然后在您的控制器上

public class HomeController
{ 
    private readonly IIndex<String, IFilter> _filters;

    public HomeController(IIndex<String, IFilter> filters)
    {
        this._filters = filters; 
    }

    public ActionResult Index()
    {
        var bikeFilter = this._filters["Bike"];
        // ...
    }
}

答案 1 :(得分:0)

Autofac没有动态实现用户定义的工厂界面的功能。它确实允许绑定代表,但它不一样。

如果你想在构造函数中接收一种工厂,那么用相关的方法从那个工厂获得单个组件,这绝对可以用Autofac。

撰写根

在这里,我将单个组件注册为单例(这是Ninject的行为,如果我能正确理解),但您可以使用任何符合您要求的生命周期选项。

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<BikeFilter>().As<IBikeFilter>().SingleInstance();
builder.RegisterType<CarFilter>().As<ICarFilter>().SingleInstance();

<强>控制器

public class HomeController
{ 
    private readonly IComponentContext _components;

    public HomeController(IComponentContext components)
    {
        _components = components; // instead of factory interface
    }

    public ActionResult Index()
    {
        var bikeFilter = _components.Resolve<IBikeFilter>();
        // ...
    }
}

BTW

我认为工厂界面是Ninject的一个很好的功能。它的另一个附加价值是允许通过IntelliSense进行探索。在您的示例中,当我键入FilterFacade和点字符时,我会看到支持的过滤器列表(CreateCarFilter,CreateBikeFilter,...)。即使我不完全熟悉项目代码库,我也可以选择一个最合适的代码库。使用Autofac,IComponentContext允许我请求任何组件,这不会帮助我找出存在哪些相关组件,或者我希望请求哪些组件。

答案 2 :(得分:0)

我写了一个NuGet来做到这一点,但是在IServiceCollection上。

https://github.com/czmirek/AddFactoryExtension

https://www.nuget.org/packages/AddFactoryExtension