【问题标题】:Autofac - resolve Generic Type through Controller constructor parameterAutofac - 通过控制器构造函数参数解析通用类型
【发布时间】:2018-05-26 10:01:30
【问题描述】:

我有抽象的泛型类

 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() - 返回我需要的实例名称(特定的默认值)。

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

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

}

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

【问题讨论】:

  • 回答这个问题会有所帮助:stackoverflow.com/questions/37835441/…
  • 谢谢,我觉得不一样...
  • 您应该改用非泛型基类或接口。你的ListController 不在乎,所以它显然不应该是通用的。
  • @Steven 是对的。此外,如果编译器要求某些东西,Autofac 也无法帮助您解决这个问题。

标签: c# generics dependency-injection constructor autofac


【解决方案1】:

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

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&lt;T&gt;。首先,您需要声明私有字段来存储对AbstractLogic&lt;T&gt; 的引用。描述了如何做到这一点的唯一方法here。之后,您需要使用 特定类型 来解决它,唯一的方法是在运行时使用反射构造此类型。这样的事情很快就会变得非常麻烦。

3) 我认为最合理的选择。您需要为AbstractLogic 引入基本非泛型类型,从中继承AbstractLogic&lt;T&gt;,将容器中的特定泛型实现注册为非泛型AbstractLogic,然后将非泛型AbstractLogic 注入您的控制器。这样,您需要将通用感知逻辑移动到通用类,同时将基本组件接口移动到非通用父 AbstractLogic。但是,这增加了一个约束:主组件非泛型接口不能以任何方式依赖于子类的特定泛型类型参数。由于我不知道您的代码的其余部分,我不能说这在您的情况下是否可行。代码的大致思路如下。

// class hierarchy
public abstract class AbstractLogic
{
    public string DoStufF()
    {
        return DoStufFInternal();
    }

    protected abstract string DoStufFInternal();
}

// Here 'where' constraint is not essential, I'm just lazy enough
// and implemented property setting in the dumbest possible way which required the constraint :)
public abstract class AbstractLogic<T> : AbstractLogic where T: class, new()
{
    protected AbstractLogic()
    {
        SomeProperty = new T();
    }

    public T SomeProperty { get; private set; }
}

public class DefaultLogic : AbstractLogic<ClassA>
{
    protected override string DoStufFInternal()
    {
        return $"Default stuff: SomeProperty = {SomeProperty.ToString()}";
    }
}

public class SpecificLogic : AbstractLogic<ClassB>
{
    protected override string DoStufFInternal()
    {
        return $"Specific stuff: SomeProperty = {SomeProperty.ToString()}";
    }
}

public class ClassA
{
    public override string ToString()
    {
        return "Class A representation";
    }
}

public class ClassB
{
    public override string ToString()
    {
        return "Class B representation";
    }
}

// registering class
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
    .Where(t => t.Name.StartsWith(Settings.GetCurrentMode().ToString()))
    .As<AbstractLogic>()
    .InstancePerLifetimeScope();

// and using it in the controller
[Route("api/[controller]")]
public class DITestController : Controller
{
    private readonly AbstractLogic _logic;

    public DITestController(AbstractLogic logic)
    {
        _logic = logic;
    }

    [HttpGet]
    public IActionResult Get()
    {
        return Ok(_logic.DoStufF());
    }
}

【讨论】:

    猜你喜欢
    • 2017-05-11
    • 2013-07-01
    • 2013-06-08
    • 2019-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多