具有命名绑定的Autofac工厂
但是,我需要在Windows和Xam.Mac之间创建可移植代码,然后我选择将我的容器切换到AutoFac(主要是由于NancyFx提供了正式的Bootstrapper),所以我使用Ninject来自IoC背景。
我在Ninject生态系统中使用的一个扩展是Ninject.Extensions.Factory,我可以注入一个抽象工厂来构造一个类的不同可能的具体实例。 我的意思的例子可以在扩展文档中找到。
我知道Autofac可以使用稍微不同的结构来实现代表使用的工厂,但根据我所需,我无法区分工厂构造参数。
首先,Autofac有可能吗? 另外,我觉得这种做法好像重新将紧耦合重新引入代码库,尽管它稍微环绕一点。 这种“限制”能否成为打破隐藏的反模式的伪装?
我不喜欢,我从来不喜欢这里引用的工厂命名约定。 在我以前的一个项目中,我们替换了部分工厂扩展来处理属性。 例如,你可以有一个带有Foo Create([Named] name)
方法的IFactory
。 我们还有其他属性,如[MatchByType]
或[MatchByName]
。 我更喜欢这种方法,因为它比较冗长,并且需要较少的先前知识来了解发生了什么。
我喜欢Autofac的代表工厂。 然而,我最关心的问题与标准Ninject工厂相同:它不重构安全,因为它将委托参数名称与构造函数参数名称匹配(因此,我们为什么根据类型而不是参数名称来匹配ninject工厂)。 为Autofac创建工厂扩展并不会那么复杂 - 基本上可以从Ninjects实现中复制它。
然而,工厂最干净的做法可能如下:
public class FooFactory : IFooFactory
{
private readonly IDependency1 dependency1;
private readonly IDependency2 dependency2;
public FooFactory(IDependency1 dependency1, IDependency2 dependency2)
{
this.dependency1 = dependency1;
this.dependency2 = dependency2
}
public IFoo Create(IParameter someParameter)
{
return new Foo(this.dependency1, this.dependency2, someParameter);
}
}
这是重构安全的。 此外,如果你使用FxCop,你也会被警告,如果你有未使用的变量。 但是,您还必须考虑是否会导致注入工厂的依赖项的正确“生命周期范围”。 保持事情清洁,这可能会引入更多的工厂。 或者,您可以选择在此处允许更紧密地耦合到DI容器,以直接从容器中检索所有依赖项。 如果您打算使用Autofac的ILifetimescope
(或Owned<T>
)来代替,那么无论如何您都会与容器紧密耦合。
最后,我个人选择坚持使用Autofac的代理工厂,并使用广泛的规格测试来确保一切按预期工作,并防止不完整的重命名重构。
编辑:今天刚刚有“自动生成的工厂”的另一个问题。 不是第一次。 这是一个参数不匹配的autofac委托工厂。 我总是发现,如果没有使用参数,DI容器不会提醒我。 通常这意味着代码中存在错误。 所以,如果我可以选择,我喜欢这样的东西:
public IFoo Create(IParameter someParameter)
{
return new Foo(this.dependency1, this.dependency2, someParameter);
}
我认为相当多的DI容器已经支持这个构造函数选择的语法。 为什么不为了晚解决? 另一种办法是拆分决议并加以约束:
Bind<Foo>().ToConstructor(c => new Foo(c.Inject, c.Inject, c.FromParameter);
然后如果工厂缺少一个参数,它可能会抛出异常。 但它仍然需要某种匹配逻辑,仍然不一定是重构安全的,等等。
我想实际回答你的第一个问题,我认为它是“如何请求工厂命名的注册”;-)据我所知,根据(命名)约定或属性,你无法做到这一点。 相反,你必须注册一个专门做这件事的工厂代表。
(注意:使用Autofac时,基本功能被命名为“键控”服务,而string-typed-key是一种特殊情况,称为“命名服务” - 参见文档)
例:
// makes types FooLicious and FooMinable available as IFoo
// similar to ninject's Bind<IFoo>().To<FooLicious>().Named("delicious");
builder.RegisterType<FooLicious>().Named<IFoo>("delicious");
builder.RegisterType<FooMinable>().Named<IFoo>("abominable");
//factory delegate definition
public delegate IFoo FooFactory(string name);
builder.Register<FooFactory>(c =>
{
var context = c.Resolve<IComponentContext>();
return name =>
{
return context.ResolveNamed<IFoo>(name);
};
});
FooFactory factory = container.Resolve<FooFactory>();
IFoo = factory("delicious"); // returns a FooDelicious
注意:我真的不知道为什么必须从c
- 它是一个IComponentContext
本身检索一个IComponentContext
。 我想我已经读过这个地方,但我不记得在哪里。 毕竟可能不需要......
可悲的是,Autofac的语法需要习惯,并且不像Ninject的语法那么简单。
替代方案:当然,您也可以直接使用DI容器而不是委托工厂...
链接地址: http://www.djcxy.com/p/65669.html上一篇: Autofac Factories with Named Bindings
下一篇: How to register types in IOC container, but in a container agnostic way?