我觉得我对使用AutoFac可以做些什么感到困惑,有人可以让我走上正轨。
我有一个基本类型
class PersonBase{
public string SaySomething(){
return "I am base";
}
}
我推导出两个具体的类
class FakePerson : PersonBase{
public override string SaySomething(){
return "I'm so Fake";
}
}
class RealPerson : PersonBase{
public override string SaySomething(){
return "I am For Real";
}
}
创建一个泛型类PersonHandler,以处理不同类型的人,并希望PersonHandler在适当的时候实例化该人,所以我不想要一个Person实例注入,只需要派生类型
class PersonHandler<T>
where T : PersonBase, new() {
T _Person;
public DoWork(){
_Person = new T();
_Person.SaySomething();
}
}
现在我尝试使用处理程序,在注册下面详细说明的类型后,会有不同的结果。
var ph = contrainer.Resolve<PersonHandler<PersonBase>>();
ph.DoWork();
我试图按以下方式注册类型
1. vBuilder.RegisterType<PersonHandler<FakePerson>>().As<PersonHandler<PersonBase>>();
这给了我一个错误,指出PersonHandler<FakePerson>
无法分配给PersonHandler<PersonBase>
(或者相反,我不会重新考虑哪个)
2. vBuilder.RegisterGeneric<typeof(PersonHandler<>)>
vBuilder.RegisterType<FakePerson>().As<PersonBase>();
这不会将PersonBase
解析为FakePerson
,而只会提供PersonHandler<PersonBase>
,因此会产生“我是基础”
3. vBuilder.RegisterGeneric(typeof(PersonHandler<FakePerson>)).As(typeof(PersonHandler<PersonBase>));
这给出了一个错误,指出PersonHandler<FakePerson>
不是开放式
所以现在我一整天都在追逐我的故事,坦率地说,它正在逐渐退出乏味,
请帮助
答案 0 :(得分:10)
(几乎)正确的解决方案就是你已经尝试过的那个:
builder.RegisterType<PersonHandler<FakePerson>>()
.As<PersonHandler<PersonBase>>();
Autofac给你一个错误的原因是C#中的泛型类不能以这种方式工作。
也就是说,你不能写:
PersonHandler<PersonBase> ph = new PersonHandler<FakePerson>();
(在IDE中试一试 - 编译器会拒绝它。)
这样做的原因是C#4中添加的必需功能的逆转仅支持接口类型。
简而言之,如果您创建IPersonHandler<T>
并将其用作服务,则上述代码将按预期工作:
interface IPersonHandler<in T>
where T : PersonBase, new() {
void DoWork();
}
请注意接口声明中的in
参数。
让PersonHandler<T>
实施IPersonHandler<T>
:
class PersonHandler<T> : IPersonHandler<T>
where T : PersonBase, new() {
然后像这样注册:
builder.RegisterType<PersonHandler<FakePerson>>()
.As<IPersonHandler<PersonBase>>();
然后您可以使用以下方式获取处理程序:
IPersonHandler<PersonBase> handler =
container.Resolve<IPersonHandler<PersonBase>>();
返回的handler
对象的类型为PersonHandler<FakePerson>
。
答案 1 :(得分:0)
当您解析使用开放泛型类型(例如PersonHandler<>
)注册的服务时,您需要指定要处理的确切关闭类型,Autofac将为您生成一个。
在这种情况下,您致电container.Resolve<PersonHandler<PersonBase>>()
,因此您返回了PersonHandler<PersonBase>
。现在,如果您查看PersonHandler
课程,并将PersonBase
替换为T
,则生成的DoWork
方法如下所示:
public DoWork(){
_Person = new PersonBase();
_Person.SaySomething();
}
因此SaySomething()
调用使用基类上的方法。
我不确定您要做什么,但看起来您想要决定在注册时使用哪个具体的PersonBase
实现。如果是这种情况,您可以尝试使用Autofac的Delegate Factory功能:
class PersonHandler
{
private readonly Func<PersonBase> createPerson;
public PersonHandler(Func<PersonBase> createPerson)
{
this.createPerson = createPerson;
}
public void DoWork()
{
PersonBase pb = this.createPerson();
Console.WriteLine(pb.SaySomething());
}
}
然后您可以按如下方式注册课程:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<RealPerson>().As<PersonBase>();
builder.RegisterType<PersonHandler>();
var context = builder.Build();
var handler = context.Resolve<PersonHandler>();
handler.DoWork();
通过更改此代码的第二行,您可以注册您实际想要在程序中使用的PersonBase
类型。