使用 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<Foo>().PropertiesAutowired();
使用DependencyResolver.Current.GetService<IFoo>();
的全局访问权限
【讨论】:
我正在使用构造函数注入,但我正在询问创建该类实例的实际过程。 创建该类实例的过程是什么意思?你想实例化什么类?你到底想做什么?提供更多信息 请看第二个灰色块。如果我按原样使用代码,我会遇到问题(当然)。然后,我提出了 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错误:实例注册只能支持SingleInstance()共享