关于c#:如何避免依赖注入构造函数的疯狂?

How to avoid Dependency Injection constructor madness?

我发现我的构造函数开始如下所示:

1
public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )

参数列表不断增加。既然"容器"是我的依赖注入容器,为什么我不能这样做:

1
public MyClass(Container con)

每节课?缺点是什么?如果我这样做,感觉就像我在使用一个美化的静电。请分享你对IOC和依赖注射疯狂的看法。


你是对的,如果你使用容器作为服务定位器,它或多或少是一个美化的静态工厂。出于很多原因,我认为这是一种反模式。

构造函数注入的一个好处是它明显地违反了单一责任原则。

当这种情况发生时,是时候重构外观服务了。简而言之,创建一个新的、更粗粒度的接口,它隐藏了您当前需要的一些或所有细粒度依赖项之间的交互。


我认为您的类构造函数不应该参考您的IOC容器周期。这表示类和容器之间不必要的依赖关系(IOC试图避免的依赖类型!).


传递参数的困难不是问题。问题是你的课做得太多了,应该多分解。

依赖注入可以作为类变得太大的早期警告,特别是因为传递所有依赖项的痛苦越来越大。


我遇到了一个类似的问题,关于基于构造函数的依赖项注入,以及传递所有依赖项的过程有多复杂。

我过去使用的方法之一是使用服务层使用应用程序外观模式。这将有一个粗糙的API。如果这个服务依赖于存储库,它将使用私有属性的setter注入。这需要创建一个抽象工厂,并将创建存储库的逻辑移动到工厂中。

详细的代码和解释可以在这里找到

复杂服务层IOC的最佳实践


注入容器是一个你最终会后悔的捷径。

过度注入不是问题,它通常是其他结构缺陷的症状,最显著的是关注点分离。这不是一个问题,但可能有很多来源,所以很难解决这个问题,因为你将不得不处理所有这些问题,有时是同时处理(想想如何清理意大利面)。

这是一份不完整的需要注意的事项清单

糟糕的域设计(聚合根…。等)

关注点(服务组合、命令、查询)分离不良。请参阅CQR和事件源。

或者制图员(小心,这些事情会给你带来麻烦)

查看模型和其他DTO(不要重复使用模型和DTO,并尽量将其保持在最低限度!!!!!)


读这整个线,两次的事情,和我认为是村里的人,他们知道什么反应,不由冰问道。 </P >

JP摩根(JP的原始问题看起来像他建构的对象发送一村的解析器,才一类的一部,但我们的assuming这类/对象是那些本身的服务,成熟的注射。如果他们是怎样诠释? </P >

JP摩根(JP),如果你要找的人到杠杆迪和欲望的荣耀(混合注射用contextual无数据,这些模式(或应该"反型"的),具体来说,是匹配的。它实际上煮下至使用包,这将支持你在这样的努力。 </P >

1
Container.GetSevice<MyClass>(someObject1, someObject2)

…………………这冰上极少的格式。在大学的编程难度相信这样的支持,添加到"可怜的绩效,会伴随着丈夫的计算机实施的方法,unattractive开源开发人员。 </P >

但它应该做的,因为在应该能够创建和记录到A厂为MyClass的ES,这厂应该能对接收到的数据输入/那是T pushed到作为一个"服务"正是通过"数据"的缘故。如果"抗冰结构"是消极的后果,然后forcing人工服务的存在(类型为低功率数据/模型冰当然负(在与你的感觉对你的DPS是麻为A类的容器。applies)一样的本能。 </P >

这可能是有帮助的框架,但是,甚至如果他们看A片丑女。例如,ninject: </P >

使用ninject [[Creating审和额外的参数的构造函数 </P >

是的,那是因为.net流行,冰和冰不动,没有为它应该是干净的,但我肯定有什么东西在什么语言的选择对你employ。 </P >


问题: </P >

1)构造函数参数与以往的增长战略。 </P >

2)如果冰继承类(如:RepositoryBase)变化的教官。 签名的原因变化的源类。 </P >

解决方案1 </P >

护照IoC Container到构造函数 </P >

为什么 </P >

  • 没有更多的参数有史以来不断增长的战略
  • 构造函数的签名变得简单

为什么不 </P >

  • 你的丈夫级紧耦合到IOC容器。(这是当1问题的原因。你想使用这类在其他项目在你使用不同的IOC容器。2。你decide to change IOC容器)
  • 你讨厌丈夫的类的描述。(你不能真的看一级建造师说什么和信息需求的功能。)
  • 类可以访问潜在的所有服务。

解决方案2 </P >

create a级的这组的所有服务和护照信息到构造函数 </P >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 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;
    }
  }

源级 </P >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  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;
      }
   }

为什么 </P >

  • 新的增级的依赖是不影响衍生类
  • 一流大学的冰agnostic IOC容器
  • 冰级描述(纵横其dependencies)。村民会议,如果你想知道什么是一流的Adepends在线信息的累积,这是在A.Dependency
  • 教官签名变得简单

为什么不 </P >

  • 要创建额外的类
  • 服务注册成为络合物(你要记录每一个X.Dependency分别)
  • 通过IoC Containerconceptually一样的混蛋
  • ………………

溶液2(虽然只是生,如果没有坚实的论据反对它的冰,然后会appreciated描述性的评论 </P >


这是使用的方法 </P >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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; }


}

这里是一个粗的方法对perform的技术和售后injections馏构造函数注入的价值观。这是全功能的程序。 </P >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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);

    }
}

我工作在一个currently爱好这厂这样的项目 http:/ / / / toolproject github.com jokine /树/核 </P >


您正在使用什么依赖注入框架?您是否尝试使用基于setter的注入?

基于构造函数的注入的好处是,对于不使用DI框架的Java程序员来说,它看起来是自然的。初始化一个类需要5件事,然后为构造函数提供5个参数。缺点是你已经注意到了,当你有很多依赖性的时候,它会变得笨拙。

使用Spring,您可以使用setter传递所需的值,并且可以使用@required annotations强制注入这些值。缺点是,您需要将初始化代码从构造函数移动到另一个方法,并使用@postconstruct标记在注入所有依赖项之后进行Spring调用。我不确定其他框架,但我认为它们做了类似的事情。

两种方法都有效,这是一个偏好问题。