C# 使用IoC将依赖项注入基类和子类?

C# 使用IoC将依赖项注入基类和子类?,c#,dependency-injection,inversion-of-control,subclass,base-class,C#,Dependency Injection,Inversion Of Control,Subclass,Base Class,如果我有一个通过构造函数依赖项注入服务的基类:是否可以在不使用:base(params)的情况下声明子类的构造函数 以及一个子类,其中注入了一些额外的依赖项: public MySubClassA : MyBaseClass { private IServiceD _serviceD; public MySubClassA (null, null, null, null) public MySubClassA (IServiceA serviceA, IServiceB se

如果我有一个通过构造函数依赖项注入服务的基类:是否可以在不使用
:base(params)
的情况下声明子类的构造函数

以及一个子类,其中注入了一些额外的依赖项:

public MySubClassA : MyBaseClass
{
   private IServiceD _serviceD;

   public MySubClassA (null, null, null, null)
   public MySubClassA (IServiceA serviceA, IServiceB serviceB, 
                       IServiceC serviceC, IServiceD serviceD)
          : base (serviceA, serviceB, serviceC)
   {
       _serviceD = serviceD;
   }
}
这里的问题是我有多个子类,现在只有10个左右,但数量会增加。每次我需要向基类添加另一个依赖项时,我必须遍历每个子类,并在那里手动添加依赖项。这本手册让我觉得我的设计有问题

那么,在子类的构造函数中没有基类所需的服务的情况下,是否可以声明
MyBaseClassA
的构造函数?例如,
MyBaseClassA
的构造函数只有以下简单得多的代码:

   public MySubClassA (null)
   public MySubClassA (IServiceD serviceD)
   {
       _serviceD = serviceD;
   }
我需要在基类中更改什么,以使依赖项注入发生在基类中,而不需要添加到子类中?我用的是Lighting

这本手册让我觉得我的电脑出了问题 设计

可能有。您给出的示例很难具体说明,但此类问题通常是由以下原因之一造成的:

  • 您使用基类来实现横切关注点(如日志记录、事务处理、安全检查、验证等),而不是decorator
  • 您使用基类来实现共享行为,而不是将该行为放置在可以注入的单独组件中
基类经常被滥用,用于向实现中添加横切关注点。在这种情况下,基类很快就变成了:一个做得太多、知道得太多的类。它违反了(SRP),导致它经常更改,变得复杂,并且难以测试

该问题的解决方案是将基类一起删除,并使用多个基类而不是单个基类。您应该为每个横切关注点编写一个decorator。这样,每个装饰者都是小而专注的,并且只有一个改变的理由(单一的责任)。通过使用,您可以创建泛型装饰器,它可以包装一整套与体系结构相关的类型。例如,一个可以包装系统中所有用例实现的装饰器,或者一个包装系统中具有特定返回类型的所有查询的装饰器

基类通常包含一组由多个实现重用的无关功能。与其将所有这些逻辑放在一个基类中(使基类成长为维护噩梦),不如将此功能提取到实现可以依赖的多个服务中

当您开始朝着这样的设计进行重构时,您经常会看到实现开始获得许多依赖项,这是一种称为构造函数过度注入的反模式。构造函数过度注入通常是类违反SRP的标志(使其变得复杂且难以测试)。但是将逻辑从基类转移到依赖项并没有使实现更难测试,事实上,具有基类的模型也有同样的问题,但不同的是依赖项被隐藏起来了

当仔细查看实现中的代码时,您经常会看到某种重复出现的代码模式。多个实现以相同的方式使用同一组依赖项。这是一个缺少抽象的信号。此代码及其依赖项可以提取到一个文档中。聚合服务减少了实现所需的依赖项数量,并包装了常见行为

使用聚合服务看起来像@SimonWhitehead在评论中提到的“包装器”,但请注意,聚合服务是关于抽象依赖项和行为的。如果您创建依赖项的“容器”,并通过公共属性公开这些依赖项以供实现使用,那么您并没有降低实现依赖的依赖项数量,也没有降低此类类的复杂性,也没有使该实现更易于测试。另一方面,聚合服务确实降低了依赖项的数量和类的复杂性,使其更容易掌握和测试


当遵循这些规则时,在大多数情况下不需要基类。

您的IoC容器不能注入属性而不是构造函数吗?我认为这会简单得多,特别是如果你是嵌套很深的类和大量的注入。。您可以将包装器作为另一种解决方案围绕这些依赖项(依赖项的容器,如果您愿意的话)。虽然我更喜欢属性方法。@SimonBelanger应用程序中的其他所有内容都使用参数注入。我认为在应用程序的某个部分尝试了属性注入,但遇到了一些我已经忘记的问题-我将不得不重新讨论这个问题。@SimonWhitehead是的,包装器可能会工作,我可以尝试创建依赖性模型,然后只有一个参数进入基类,如果我需要添加更多的依赖项,我只需将它们添加到模型中,所有的子类都不需要更改,不管怎样,拥有这么多的子类无疑是对设计疏忽的提示(回答您的一个问题)@SimonWhitehead选项也会更简单,但随后您将自己绑定到一个服务定位器。+1来引入横切关注点和使用装饰器的解决方案。(事实上,它应该+2)我认为清理并创建“上帝课堂”是个好主意——然后我再次遇到这个答案,并意识到这是一个愚蠢的想法:D
   public MySubClassA (null)
   public MySubClassA (IServiceD serviceD)
   {
       _serviceD = serviceD;
   }