8

泛型类和依赖注入之间有什么区别吗?它们不是实现控制反转的方法吗

泛型类不是实现依赖注入并增加编译时安全性的方法吗?

例如,如果我有一个节点类,那么我可以定义如下

class Node<T> where T : ISomeInterface
{
  ..
  ..
}

class Node
{
   ISomeInterface obj
   public Node(ISomeInterface inject)
   {
       obj = inject;
   }
}

更新 2 与新

class Node<T> where T : ISomeInterface, new()
{
  ISomeInterface obj
  public Node()
  {
     obj = new T();
  }
}

更新 3 @akim:我已经做了你要求使用 Generics Repository using Generics 的示例

Interface IRepository 
{   
      public DataTable GetAll();
}

public class ProductRep : IRepository
{ 
       public DataTable GetAll()
       {
            //implementation
       }
}

public class MockProductRep : IRepository
{ 
       public DataTable GetAll()
       {
            //mock implementation
       }
}

public class Product<T> where T : IRepository, new()
{
    IRepository repository = null
     public Product()
     {
       repository = new T();
     }
    public List<Product> GetProduct()
    {
      DataTable prodlst =  repository.GetAll();
      //convert to List of products now
    }
}


//so while using the Product class, client would Supply ProductRep class and in NUnit you //would supply MockProductRep class

Product<ProductRep> obj = new ProductRep<ProductRep>();
List<Product> lst = obj.GetProduct();

//in NUnit
Product<MockProductRep> obj = new ProductRep<MockProductRep>();
List<Product> lst = obj.GetProduct();
4

3 回答 3

3

泛型引入了类型参数的概念,这使得设计类和方法成为可能,这些类和方法延迟一种或多种类型的规范,直到类或方法由代码msdn声明和实例化。并且泛型及其所有限制和检查在编译期间使用静态分析应用。

另一方面,依赖注入是一种软件设计模式,它允许在运行时而不是编译时 wiki中选择组件。并且对象耦合在运行时由汇编程序对象绑定,并且通常在编译时使用静态分析 wiki不知道。

回答您的问题:一个在编译时使用静态分析应用,另一个在运行时使用 XML 或代码内配置应用(它也应该对编译有效)。使用 依赖注入关于绑定的决定将被推迟,直到从上下文中获得更多信息或配置。所以泛型和依赖注入是不同的,用于不同的目的。

示例 #3 答案

让我们更进一步,提供Repository<Entity>Controller考虑它的用法。你将如何实现控制器的构造函数:

public ControlFreakController<Repository<Entity>>()
{
    this.repository = new Repository<Entity>(); // here is a logical problem
}

或者

public ControllerWithInjection(IRepository repository)
{
   this.repository = repository;
}

ControlFreakController如果它取决于Repository<Entity>(字面意思是硬编码) ,你将如何覆盖测试?如果Repository<Entity>没有默认构造函数,并且有自己的依赖项和生命周期(例如,应该只有一个存储库代表 HTTP 请求)怎么办?如果第二天需要审核工作Repository<Entity>怎么办?

于 2012-07-30T04:43:51.460 回答
3

他们不一样。泛型类型允许您定义可应用于各种其他类型的功能。但是,当您实例化泛型类时,编译器会引用作为泛型参数传递的实际类型。所以声明是静态的,编译后不能改变。例如,我可以编写实例化您的 Node 类的代码:

Node<SomeImplementation> node1 = new Node<SomeImplementation>();
Node<SomeOtherImplementation> node2 = new Node<SomeOtherImplementation>();

我在不同的场景中重用你的 Node 类,但是一旦我编译了我的程序集,我就不能改变我的变量的泛型类型(node1 和 node2)。

另一方面,依赖注入(和 IoC 容器)允许您在运行时更改应用程序的功能。您可以使用依赖注入ISomeInterface在运行时用完全不同的实现交换一个实现。例如,在您的第二个节点类中,我可以使用 IoC 容器来创建节点类......类似于:

Node n = Container.Create<Node>();

然后 IoC 容器会根据一些配置确定如何实例化 Node 类。它确定构造函数需要 的实现ISomeInterface,并且知道如何在运行时构建实现。我可以更改 IoC 容器的配置并执行相同的程序集/代码,并创建不同的实现ISomeInterface并将其传递给 Node.js 的构造函数。

这在单元测试中很有用,因为您可以模拟应用程序的某些部分,以便可以测试一个特定的类。例如,您可能想要测试一些通常访问数据库的业务逻辑。在您的单元测试中,您可以模拟您的数据访问逻辑并注入新功能,以返回测试每个特定业务案例所需的“静态”数据。这打破了您的测试对数据库的依赖,并允许进行更准确/可维护的测试。

编辑

关于您的更新,可能并不总是需要无参数构造函数限制。您可能有一个需要参数的类(由您或第三方编写)。要求类实现无参数构造函数可能会影响应用程序的完整性。DI 模式背后的想法是您的 Node 类不需要知道该类是如何实际创建的。

假设您有许多层的类/依赖项。对于泛型类型,它可能如下所示:

class MyClass<T>
    where T : IUtilityClass
{
    ...
}

class UtilityClass<T> : IUtilityClass
    where T : IAnotherUtilityClass
{
    ...
}

class AnotherUtilityClass : IAnotherUtilityClass
{
    ...
}

在这种情况下,MyClass 使用 UtilityClass,而 UtilityClass 依赖于 AnotherUtilityClass。因此,当您声明 时MyClass,您必须知道每一个依赖项......不仅是 的依赖项MyClass,还有UtilityClass. 这个声明看起来像这样:

MyClass<UtilityClass<AnotherUtilityClass>> myTestClass =
    new MyClass<UtilityClass<AnotherUtilityClass>>();

当您添加越来越多的依赖项时,这会变得很麻烦。使用 DI,您的调用者不需要知道任何嵌套依赖项,因为 IoC 容器会自动计算出它们。您只需执行以下操作:

MyClass myTestClass = Container.Create<MyClass>();

无需了解有关 MyClass 或其实用程序类的详细信息。

IoC 容器通常还有其他好处,例如,它们中的许多都提供了面向切面编程的形式。它们还允许您指定对象的生命周期,因此对象可以是单例(只会创建一个实例,并且将相同的实例返回给所有调用者)。

于 2012-07-30T04:28:23.487 回答
0

我假设你的意思是你的泛型类看起来像这样:

class Node<T> where T : ISomeInterface {
    T obj;

    public Node(T inject) {
        obj = inject;
    }
}

..在这种情况下,您只是为依赖注入打开了一个泛型类型(有限制)。您还没有发现依赖注入的不同“方法”——它仍然是依赖注入。

这在“现实世界”场景中不是很有用。您已经假设类型参数将如何纯粹基于注入和限制它来使用。此外,您只能将一种单一类型的对象注入其中,这是一个非常糟糕的假设。

使用 new() 进行更新后,您会遇到更多问题。您的注入类型必须允许无参数构造。这进一步限制了你。

于 2012-07-30T04:31:24.963 回答