C# 如何避免依赖注入构造函数的疯狂?
我发现我的构造函数开始像这样:C# 如何避免依赖注入构造函数的疯狂?,c#,java,dependency-injection,inversion-of-control,ioc-container,C#,Java,Dependency Injection,Inversion Of Control,Ioc Container,我发现我的构造函数开始像这样: public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... ) 随着参数列表的不断增加。既然“容器”是我的依赖注入容器,为什么我不能这样做: public MyClass(Container con) 每节课?缺点是什么?如果我这样做,感觉就像我在使用美化的静态。请分享您对IoC和依赖注入疯狂的看法。如果您将容器用作服务定位器,它或多或少是一个美化的静态工厂,这是正确的。有很多原因(也
public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )
随着参数列表的不断增加。既然“容器”是我的依赖注入容器,为什么我不能这样做:
public MyClass(Container con)
每节课?缺点是什么?如果我这样做,感觉就像我在使用美化的静态。请分享您对IoC和依赖注入疯狂的看法。如果您将容器用作服务定位器,它或多或少是一个美化的静态工厂,这是正确的。有很多原因(也可以从我的书中看到) 构造函数注入的一个极好的好处是,它使违反
当这种情况发生时,是时候采取行动了。简而言之,创建一个新的、更粗粒度的接口,该接口隐藏当前所需的部分或所有细粒度依赖项之间的交互。我认为类构造函数不应该引用IOC容器周期。这表示类和容器之间存在不必要的依赖关系(IOC试图避免的依赖关系类型!) 传递参数的困难不是问题所在。问题是你的班级做得太多了,应该进一步细分
依赖项注入可以作为类变得太大的早期警告,特别是因为传递所有依赖项的痛苦越来越大。您使用的是什么依赖项注入框架?您是否尝试过使用基于setter的注入 基于构造函数的注入的好处是,对于不使用DI框架的Java程序员来说,它看起来很自然。初始化一个类需要5件事,然后构造函数有5个参数。缺点是您已经注意到,当您有很多依赖项时,它会变得很笨拙 使用Spring,您可以使用setter传递所需的值,并且可以使用@required注释强制注入它们。缺点是,您需要将初始化代码从构造函数移动到另一个方法,并在注入所有依赖项后通过@PostConstruct标记Spring调用它。我不确定其他框架,但我认为它们也有类似的功能
这两种方法都有效,这是一个偏好问题。我遇到了一个类似的问题,关于基于构造函数的依赖项注入,以及传递所有依赖项有多复杂 我过去使用的方法之一是使用服务层使用应用程序外观模式。这将有一个粗糙的API。若此服务依赖于存储库,它将使用私有属性的setter注入。这需要创建一个抽象工厂,并将创建存储库的逻辑移动到工厂中 详细的代码和解释可以在这里找到 问题: 1) 具有不断增加的参数列表的构造函数 2) 若继承了类(例如:
RepositoryBase
),则更改构造函数
签名导致派生类中的更改
解决方案1
将IoC容器传递给构造函数
为什么
- 不再增加参数列表
- 构造函数的签名变得简单
- 使类与IoC容器紧密耦合。(当1.您想在使用不同IoC容器的其他项目中使用该类时会出现问题。2.您决定更改IoC容器)
- 使您的类不那么具有描述性。(您无法真正查看类构造函数并说出其功能所需的内容。)
- 类可以潜在地访问所有服务
public abstract class EFRepositoryBase
{
public class Dependency
{
public DbContext DbContext { get; }
public IAuditFactory AuditFactory { get; }
public Dependency(
DbContext dbContext,
IAuditFactory auditFactory)
{
DbContext = dbContext;
AuditFactory = auditFactory;
}
}
protected readonly DbContext DbContext;
protected readonly IJobariaAuditFactory auditFactory;
protected EFRepositoryBase(Dependency dependency)
{
DbContext = dependency.DbContext;
auditFactory= dependency.JobariaAuditFactory;
}
}
派生类
public class ApplicationEfRepository : EFRepositoryBase
{
public new class Dependency : EFRepositoryBase.Dependency
{
public IConcreteDependency ConcreteDependency { get; }
public Dependency(
DbContext dbContext,
IAuditFactory auditFactory,
IConcreteDependency concreteDependency)
{
DbContext = dbContext;
AuditFactory = auditFactory;
ConcreteDependency = concreteDependency;
}
}
IConcreteDependency _concreteDependency;
public ApplicationEfRepository(
Dependency dependency)
: base(dependency)
{
_concreteDependency = dependency.ConcreteDependency;
}
}
为什么
- 向类添加新的依赖项不会影响派生类
- 类与IoC容器无关
- 类是描述性的(在其依赖性方面)。按照惯例,如果您想知道
所依赖的类,则该信息将累积在A
A.Dependency
- 构造函数签名变得简单
- 需要创建额外的类
- 服务注册变得复杂(您需要分别注册每个
)X.Dependency
- 概念上与传递
IoC容器相同
- 李>
不过,解决方案2只是一个原始的解决方案,如果有确凿的证据反对它,那么描述性的评论将不胜感激这是我使用的方法
public class Hero
{
[Inject]
private IInventory Inventory { get; set; }
[Inject]
private IArmour Armour { get; set; }
[Inject]
protected IWeapon Weapon { get; set; }
[Inject]
private IAction Jump { get; set; }
[Inject]
private IInstanceProvider InstanceProvider { get; set; }
}
下面是一个粗略的方法,如何执行注入,并在注入值后运行构造函数。这是一个功能齐全的程序
public class InjectAttribute : Attribute
{
}
public class TestClass
{
[Inject]
private SomeDependency sd { get; set; }
public TestClass()
{
Console.WriteLine("ctor");
Console.WriteLine(sd);
}
}
public class SomeDependency
{
}
class Program
{
static void Main(string[] args)
{
object tc = FormatterServices.GetUninitializedObject(typeof(TestClass));
// Get all properties with inject tag
List<PropertyInfo> pi = typeof(TestClass)
.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
.Where(info => info.GetCustomAttributes(typeof(InjectAttribute), false).Length > 0).ToList();
// We now happen to know there's only one dependency so we take a shortcut just for the sake of this example and just set value to it without inspecting it
pi[0].SetValue(tc, new SomeDependency(), null);
// Find the right constructor and Invoke it.
ConstructorInfo ci = typeof(TestClass).GetConstructors()[0];
ci.Invoke(tc, null);
}
}
公共类InjectAttribute:属性
{
}
公共类TestClass
{
[注入]
私有依赖关系sd{get;set;}
公共测试类()
{
控制台写入线(“ctor”);
控制台写入线(sd);
}
}
公共类依赖项
{
}
班级计划
{
静态void Main(字符串[]参数)
{
object tc=FormatterServices.GetUninitializedObject(typeof(TestClass));
//使用inject标记获取所有属性
列表pi=typeof(TestClass)
.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
.Where(info=>info.GetCustomAttributes(typeof(InjectAttribute),false).Length>0.ToList();
//我们现在碰巧知道只有一个依赖项,所以为了这个示例,我们选择了一个快捷方式,只设置值,而不检查它
pi[0].SetValue(tc,new-SomeDependency(),null);
//找到正确的构造函数并调用它。
ConstructorInfo ci=typeof(TestClass).GetConstructors()[0];
ci.Invoke(tc,null);
}
}
我目前正在做一个爱好项目,它是这样工作的
我把这整条线索读了两遍,然后
Container.GetSevice<MyClass>(someObject1, someObject2)