Autofac - 通过Controller构造函数参数解析Generic Type

时间:2018-05-21 10:52:30

标签: c# generics dependency-injection constructor autofac

我有抽象的通用类

 public abstract class AbstractLogic<T> {}

两个实现

DefaultLogic  : AbstractLogic<ClassA>{}
SpecificLogic : AbstractLogic<ClassB>{}

正如我们所看到的,如果我想创建其中的一个实例,我可以轻松地完成它,而无需指定开放的泛型类。

DefaultLogic logic= new DefaultLogic();

现在我需要在DI的帮助下创建每个实例。 所以,我注册了那样的类型

    var logicList= new[]
        {
            Assembly.GetAssembly(typeof(DefaultLogic)),
            Assembly.GetAssembly(typeof(SpecificLogic))
        };
        builder.RegisterAssemblyTypes(logicList).AsClosedTypesOf(typeof(AbstractLogic<>))
            .Where(t => t.Name.StartsWith(Settings.GetCurrentMode().ToString()));

Settings.GetCurrentMode() - 返回一个我需要的实例名称(Default of Specific)。

不,我想将服务注入控制器,以使其能够加载所需的逻辑服务。

public class ListController : Controller
{
    private AbstractLogic<???> _logic;
    public ListController(AbstractLogic<???> logic)
        {
            _logic = logic;
        }

}

编译器要求我定义模型而不是???。但是,我并不需要它,因为Implementation ob抽象类已经选择了一个开放的泛型类型而不是继承。还有其他方法如何使用autofac解决所需的逻辑?

1 个答案:

答案 0 :(得分:0)

在我看来,你在这里有三个或多或少的真实选择。

1)使控制器通用,然后将控制器的类型参数传递给注入类型本身(见下文)。这样控制器就会知道特定的类型T,并且能够在没有任何奇怪的舞蹈的情况下使用它。然而,接下来的问题是 - 如何解释所有这些东西到一个将解决这样一个控制器的框架?默认情况下,DotNet Core不支持通用控制器。幸运的是,很有可能做到这一点。您可以通过in this answer进一步阅读有关它的一些详细信息link to Microsoft's documentation。但这并不简单,所以这对你的任务来说太过分了......我只是不确定你的任务到底是什么。

[Route("api/[controller]")]
public class ValuesController<T> : Controller where T: class, new()
{
    private readonly AbstractLogic<T> _logic;

    public ValuesController(AbstractLogic<T> logic)
    {
        _logic = logic;
    }

2)使用反射来解析AbstractLogic<T>。首先,您需要声明私有字段以存储对AbstractLogic<T>的引用。描述here的唯一方法是如何完成。之后,您需要使用特定类型来解决它,唯一的方法是在运行时使用反射构造此类型。这样的事情很快就变得非常麻烦。

3)我认为最合理的选择。您需要为AbstractLogic引入基本非泛型类型,从中继承AbstractLogic<T>,将容器中的特定泛型实现注册为非泛型AbstractLogic,然后只注入非泛型{ {1}}进入你的控制器。这样,您需要将通用感知逻辑移动到泛型类,同时将基本组件接口移动到非泛型父AbstractLogic。但是,这会增加一个约束:主要组件非泛型接口不得以任何方式依赖于子类的特定泛型类型参数。由于我不知道你的其余代码,我不能说你的情况是否可行。代码的一般概念如下。

AbstractLogic