使用 Autofac 创建具有依赖关系的类的实例

Posted

技术标签:

【中文标题】使用 Autofac 创建具有依赖关系的类的实例【英文标题】:Create instance of a class with dependencies using Autofac 【发布时间】:2012-05-29 12:38:55 【问题描述】:

问题:

假设类:

public class MyAwesomeClass

   private IDependCls _dependCls;
   public MyAwesomeClass(IDependCls dependCls)
   
       _dependCls = dependCls;
   


我需要在其他地方获取该类的实例,如下所示:

public class SomewhereElse

    public void AwesomeMethod()
    
        //...
        // AwesomeStuff
        //...

        var GetErDone = new MyAwesomeClass();  // PROBLEM! No constructor with 0 arguements
    

问题是,我是吗

建议的解决方案 1:

A) 必须创建一个额外的构造函数来解决依赖关系?例如:

   public MyAwesomeClass() // new constructor
   
       _dependCls = DependencyResolver.Current.GetService<IDependCls>();
   


public class SomewhereElse

    public void AwesomeMethod()
    
        var GetErDone = new MyAwesomeClass();  // IT WORKS!!
    

建议的解决方案 2:

B) 在var GetErDone 之前使用AwesomeMethod 中的解析器

public class SomewhereElse

    public void AwesomeMethod()
    
        var depCls = _dependCls = DependencyResolver.Current.GetService<IDependCls>();
        var GetErDone = new MyAwesomeClass(depCls);  // IT WORKS!!
    

Autofac 解决方案?

C) 其他 Autofac 方式?

如果可能的话,寻找最佳实践以及良好的 Autofac 解决方案。我认为第一种方式是最糟糕的,因为可选的依赖项可能会导致很多混乱。

总结:

MyAwesomeClass 有依赖关系时,我如何获得new MyAwesomeClass()

【问题讨论】:

你说的真的是可选吗?如果它确实是可选的,您可能需要查看属性注入。如果不是,并且您的 ctor 由于依赖项过多而变得杂乱无章,则可能您的班级做得太多(另请参阅this answer)。 我没有关于构造函数混乱的问题,而不是创建需要构造函数注入的类的实例。 感谢您没有发布解决方案答案。不像其他任何机构都有这个问题... /s 【参考方案1】:

看看Composition Root 模式。

你是对的,拉起依赖解决方案只会将问题转移到另一个地方。但是,如果您继续在对象图中向上移动它,您将到达应用程序的入口点。在那里你将组成你的对象图。

将其与Service Locator anti-pattern(在您的案例中使用客户端类中的DependencyResolver)进行比较,您会发现Composition Root 是一个出色的解决方案。

【讨论】:

感谢您的回复。 +1,因为您实际上掌握了这个概念,并感谢您的文章。所以我想这将不可避免地发生?我将更多地阅读这种方法,但我认为你所说的实际组合根应该是绑定本身的声明。否则,您将打破单一职责和关注点分离规则。 是的,Composition Root 被抽象地定义为一个“位置”,您可以将其拆分为多个类,但重要的是它们包含在同一个程序集中。文章作者 Mark Seemann 写了a great book 关于 DI 顺便说一句。 @Mihalis - 您是否曾经使用组合根模式或其他方式获得令人满意的解决方案。您的示例代码很容易理解,我想查看第三种解决方案的代码 - 比 我想每个人可能都会同意,在构造函数中使用 DI,正如 Seemann 或多或少解释的那样,似乎是最好的解决方案。但是,在某些情况下,您可能需要动态获取控制器实例,此时您需要一个无参数构造函数,然后服务定位器似乎是我们唯一的选择? 无示例 + 死链接 + OP 从未发布答案 = 糟糕的问题/答案。【参考方案2】:

首先,除了构造函数注入之外,您还可以使用property injection 和method injection。但是构造函数注入是最常见也是最快的方法,所以我建议坚持下去。

您需要做的第二件事是在 Autofac 容器中注册您的 MyAwesomeClass 及其依赖项,他们的主页上有一些不错的 examples。

最后一件事——你不应该直接创建MyAwesomeClass的实例——改用Autofac。这是一个更新的示例:

public void AwesomeMethod()

    //...
    // AwesomeStuff
    //...

    var GetErDone = DependencyResolver.Current.GetService<MyAwesomeClass>();

【讨论】:

这会创建一个新实例还是已经注册的服务?【参考方案3】:

您可以使用反射创建一个新的“MyAwesomeClass”实例,使用 Autofac 解析构造函数参数。

    public static T Instance<T>() where T : class
    
        Type instanceType = typeof(T);
        ConstructorInfo constructorInfo = instanceType.GetConstructors()[0];
        ParameterInfo[] constructorParamsInfo = constructorInfo.GetParameters();
        object[] constructorParams = new object[constructorParamsInfo.Length];

        for (int i = 0; i < constructorParamsInfo.Length; i++)
        
            var parameterInfo = constructorParamsInfo[i];
            var type = parameterInfo.ParameterType;
            constructorParams[i] = Container.Resolve(type);
        

        object instance = Activator.CreateInstance(instanceType, constructorParams);

        return (T)instance;
    

【讨论】:

【参考方案4】:

如果你想通过Autofac自动解析实例,你只能从中选择

注入类的构造函数

通过使用注入属性

var builder = new ContainerBuilder();

builder.RegisterType&lt;Foo&gt;().PropertiesAutowired();

使用DependencyResolver.Current.GetService&lt;IFoo&gt;();的全局访问权限

【讨论】:

我正在使用构造函数注入,但我正在询问创建该类实例的实际过程。 创建该类实例的过程是什么意思?你想实例化什么类?你到底想做什么?提供更多信息 请看第二个灰色块。如果我按原样使用代码,我会遇到问题(当然)。然后,我提出了 2 个我不喜欢的解决方案,并要求提供第 3 个解决方案 - 或者确认我提出的 2 个解决方案之一是标准做法。我将更新答案以实际包含我的解决方案供您查看 如果你想在方法内部实例化 MyAwesomeClass,最好的方法是使用 DependencyResolver。但是,我认为在你的方法中实例化某些东西是不好的做法。您应该创建接口 IMyAwesomeClass 并在使用它的类中使用 ctor 注入。之后,您可以在方法中使用类字段 是的,DependencyResolver 可以在 2 个不同的地方使用(我提出的解决方案)。但是,我想要一个不涉及 DependencyResolver 的解决方案。关于界面,请参阅我对@Peter Lillevold 答案的评论。问题保持不变,只是高了一级。 (SomewhereElse 类在某些时候需要得到new SomewhereElse(),所以同样的问题)【参考方案5】:

在包含MyAwesomeMethod 的类中,将MyAwesomeClass 作为构造函数依赖项。 Autofac 将负责实例化。

【讨论】:

是的,但这只是将问题提高了一级,这就是我的重点。如果我想创建一个包含 MyAwesomeMethod 的类的实例怎么办?【参考方案6】:

我知道这个问题很老,但我在描述类动态实例化的 autofac 文档上找到了一个非常有用的链接。

Autofac Dynamic Instantiation

也许对某人有帮助。

【讨论】:

以上是关于使用 Autofac 创建具有依赖关系的类的实例的主要内容,如果未能解决你的问题,请参考以下文章

Autofac总结

autofac 多个dbcontext 上下文不一致

Autofac错误:实例注册只能支持SingleInstance()共享

Activator.CreateInstance - 如何创建具有参数化构造函数的类的实例

如何在C#中使用具有存储库模式的依赖注入(AutoFac)

IOC容器之Autofac