使用AutoFac注入通用类型参数

ric*_*rdo 3 generics dependency-injection autofac

我觉得我对使用AutoFac可以做些什么感到困惑,有人可以让我走上正轨.

我有一个基本类型

class PersonBase{ 
    public string SaySomething(){
       return "I am base";
    }
}
Run Code Online (Sandbox Code Playgroud)

我推导出两个具体的课程

class FakePerson : PersonBase{
    public override string SaySomething(){
       return "I'm so Fake";
    }
}

class RealPerson : PersonBase{
    public override string SaySomething(){
       return "I am For Real";
    }
}
Run Code Online (Sandbox Code Playgroud)

创建一个泛型类PersonH​​andler,以处理不同类型的人,并希望PersonH​​andler在适当的时候实例化该人,所以我不想要一个Person实例注入,只需要派生类型

class PersonHandler<T>
    where T : PersonBase, new() {

    T _Person;    

    public DoWork(){
        _Person = new T();
        _Person.SaySomething();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我尝试使用处理程序,在注册下面详细说明的类型后,会有不同的结果.

var ph = contrainer.Resolve<PersonHandler<PersonBase>>();
ph.DoWork();
Run Code Online (Sandbox Code Playgroud)

我试图按如下方式注册类型

1. vBuilder.RegisterType<PersonHandler<FakePerson>>().As<PersonHandler<PersonBase>>();
Run Code Online (Sandbox Code Playgroud)

这给了我一个错误,说明PersonHandler<FakePerson>不能分配PersonHandler<PersonBase>(或者反过来我不会重新分配哪个)

2. vBuilder.RegisterGeneric<typeof(PersonHandler<>)>
   vBuilder.RegisterType<FakePerson>().As<PersonBase>();
Run Code Online (Sandbox Code Playgroud)

这不能解决PersonBaseFakePerson,但只是给PersonHandler<PersonBase>,所以它导致"我基地"

3. vBuilder.RegisterGeneric(typeof(PersonHandler<FakePerson>)).As(typeof(PersonHandler<PersonBase>));
Run Code Online (Sandbox Code Playgroud)

这给出了一个错误,说这PersonHandler<FakePerson>不是一个开放类型

所以现在我整天都在追逐自己的故事,坦率地说,它正在逐渐退出繁琐,

请帮忙

Nic*_*rdt 10

(差不多)正确的解决方案是您已尝试过的解决方案:

builder.RegisterType<PersonHandler<FakePerson>>()
    .As<PersonHandler<PersonBase>>();
Run Code Online (Sandbox Code Playgroud)

Autofac给你一个错误的原因是C#中的泛型类不能以这种方式工作.

也就是说,你不能写:

PersonHandler<PersonBase> ph = new PersonHandler<FakePerson>();
Run Code Online (Sandbox Code Playgroud)

(在IDE中试一试 - 编译器会拒绝它.)

这样做的原因是,C#4中添加的必需功能的逆转仅支持接口类型.

简而言之,如果您创建IPersonHandler<T>并使用它作为服务,那么上面的代码将按预期工作:

interface IPersonHandler<in T>
    where T : PersonBase, new() {

    void DoWork();
}
Run Code Online (Sandbox Code Playgroud)

请注意in接口声明中的参数.

制作PersonHandler<T>工具IPersonHandler<T>:

class PersonHandler<T> : IPersonHandler<T>
    where T : PersonBase, new() {
Run Code Online (Sandbox Code Playgroud)

然后像这样注册:

builder.RegisterType<PersonHandler<FakePerson>>()
    .As<IPersonHandler<PersonBase>>();
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用以下方式获取处理

IPersonHandler<PersonBase> handler =
    container.Resolve<IPersonHandler<PersonBase>>();
Run Code Online (Sandbox Code Playgroud)

返回的handler对象将是类型PersonHandler<FakePerson>.