在C#中使用泛型 - 从Generic类调用Generic类

时间:2010-07-28 13:51:13

标签: c# .net generics .net-4.0

我有一个类似于以下的类:

public abstract class Manager<T, TInterface> : IManager<T> where TInterface : IRepository<T>
{
    protected abstract TInterface Repository { get; }

    public virtual List<T> GetAll()
    {
        return Repository.GetAll();
    }
}

这很好用,但是,有没有办法摆脱抽象类声明中的TInterface以及扩展我的泛型抽象类的结果类:

public class TestManager : Manager<TestObject, ITestRepository>, ITestManager

我被迫使用ITestRepository并将Repository属性设为抽象,因为它可以包含我需要了解并能够调用的自定义方法。

当我继续构建图层时,我将不得不在整个堆栈中继续执行此过程。例如,如果我有一个通用的抽象控制器或服务层:

public class TestService : Service<TestObject, ITestManager>, ITestService

有没有更好的方法来执行此操作,或者这是允许泛型类调用另一个泛型类的最佳做法?

2 个答案:

答案 0 :(得分:1)

似乎您要做的就是使Manager<T>可测试,并使用模拟作为存储库,您可以查询特殊成员。

如果是这种情况,也许您可​​以将设计更改为:

public class Manager<T> : IManager<T> {
  protected IRepository<T> Repository { get; set; }
  // ...
  public virtual List<T> GetAll() {
    return Repository.GetAll();
  }
}

现在,测试的所有细节都在测试子类中:

public class TestingManager<T> : Manager<T> {
  public new ITestRepository<T> Repository {
    get {
      return (ITestRepository<T>)base.Repository;
    }
    set {
      base.Repository = value;
    }
  }
}

编写单元测试时,创建TestingManager<T>个实例(通过TestingManager<T>声明的变量和字段引用),并为它们提供测试存储库。每当您查询他们的Repository时,您将始终获得一个强类型的测试存储库。

<强>更新

还有另一种解决方法,没有子类。您将存储库对象声明为传递给Manager<T>的测试存储库,并直接查询它们,而不通过Manager<T>

[Test]
public void GetAll_Should_Call_GetAll_On_Repository_Test() {
  var testRepository = new TestRepository();
  var orderManager = new Manager<Order>(testRepository);
  // test an orderManager method
  orderManager.GetAll();
  // use testRepository to verify (sense) that the orderManager method worked
  Assert.IsTrue(testRepository.GetAllCalled);
}

答案 1 :(得分:0)

不,你无法解决它。你可以尝试,但结果将是丑陋的,在某种程度上是不正确的。原因是你要求泛型不是通用的,但仍然是通用的。

如果一个新类在继承或组合中使用泛型类,并且它本身不足以指定它所使用的泛型类的类型参数,那么它本身必须是通用的。它类似于方法调用链,其中方法可以将参数传递给另一个方法。它不能构成内部方法的参数,但必须将它们作为参数本身从调用者那里知道它们是什么。类型参数是相同的。

做的一件事让这感觉像代码味道的事实是你不能拥有Manager&lt;,&gt;类型的变量。它必须完全按类型指定。我提出的一个解决方案是使用泛型类实现的非泛型接口。这些接口尽可能多地具有泛型类的公共接口(它们不能具有引用类型参数的方法或属性)。然后,您可以传递接口类型的变量,而不必指定类型参数。

示例:

interface IExample {
    string Name { get; }
    void SomeNonGenericMethod(int i);
}

class Example<T> : IExample {
    public string Name { get { ... } }

    public void SomeNonGenericMethod(int i) {
        ...
    }

    public T SomeGenericMethod() {
        ...
    }
}