4 c# dependency-injection inversion-of-control autofac
我想在 Autofac 中实现工厂模式。这是在 Ninject 中完成的方式:
Bind<ICarFilter>().To<CarFilter >();
Bind<IBikeFilter>().To<BikeFilter>();
Bind<IFilterFacade>().ToFactory().InSingletonScope();
Run Code Online (Sandbox Code Playgroud)
这是 IFilterFacade 的定义
public interface IFilterFacade
{
ICarFilter CreateCarFilter();
IBikeFIlter CreateBikeFilter();
}
Run Code Online (Sandbox Code Playgroud)
如果我想要一个 CarFilter 类型的实例,我需要做的就是以下内容:
public class HomeController(IFilterFacade filterFacade)
{
FilterFacade = filterFacade;
}
public IFilterFacade FilterFacade { get;set; }
public ActionResult Index()
{
var bikeFilter = FilterFacade.CreateBikeFilter();
}
Run Code Online (Sandbox Code Playgroud)
任何如何在 AutoFac 中执行此操作的示例。我检查了 AutoFac 文档,但找不到答案或示例。
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>();
}
}
Run Code Online (Sandbox Code Playgroud)
然后像这样注册它:
builder.RegisterType<FilterFactory>().As<IFilterFactory>();
builder.RegisterType<BikeFilter>().As<IBikeFilter>();
builder.RegisterType<CarFilter>().As<ICarFilter>();
Run Code Online (Sandbox Code Playgroud)
并以这种方式使用它
public class HomeController
{
private readonly IFilterFactory _filters;
public HomeController(IFilterFactory filters)
{
this._filters = filters;
}
public ActionResult Index()
{
var bikeFilter = this._filters.Get<IBikeFilter>();
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
我将该Create方法重命名为,Get因为该方法将在生命周期范围内查找一个实例并仅在需要时创建一个。
另一种可能的解决方案可能是使用命名和键控服务以及内置IIndex类型。
builder.RegisterType<BikeFilter>().Named<IFilter>("Bike");
builder.RegisterType<CarFilter>().Named<IFilter>("Car");
Run Code Online (Sandbox Code Playgroud)
然后在你的控制器上
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"];
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
Autofac没有动态实现用户定义工厂接口这样的功能。它确实允许绑定到委托,但它不一样。
如果你想在构造函数中接收一种工厂,然后在相关方法中从该工厂中获取各个组件,使用 Autofac 绝对可以。
成分根
在这里,我将各个组件注册为单例(这是 Ninject 的行为,如果我理解正确的话),但您可以使用任何适合您要求的生命周期选项。
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<BikeFilter>().As<IBikeFilter>().SingleInstance();
builder.RegisterType<CarFilter>().As<ICarFilter>().SingleInstance();
Run Code Online (Sandbox Code Playgroud)
控制器
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>();
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
顺便提一句
我认为工厂界面是 Ninject 的一个很好的功能。它的另一个附加价值是允许通过 IntelliSense 进行探索。在您的示例中,当我键入FilterFacade点字符时,我会看到受支持的过滤器列表(CreateCarFilter、CreateBikeFilter,...)。这样,即使我不完全熟悉项目代码库,我也可以选择最适合的一个。使用 Autofac,IComponentContext我可以请求任何组件,但这并不能帮助我找出存在哪些相关组件,或者我应该请求哪些组件。