在C#中使用泛型-从泛型类调用泛型类
我的课程与以下内容类似:在C#中使用泛型-从泛型类调用泛型类,c#,.net,generics,.net-4.0,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 Reposi
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();
}
}
公共抽象类管理器:IManager,其中TInterface:IRepository
{
受保护的抽象TInterface存储库{get;}
公共虚拟列表GetAll()
{
返回Repository.GetAll();
}
}
这非常好,但是,有没有一种方法可以避免在抽象类声明和扩展我的泛型抽象类的结果类中使用TInterface:
public class TestManager : Manager<TestObject, ITestRepository>, ITestManager
公共类测试管理器:管理器,ITestManager
我被迫使用ITestRespository并将存储库属性抽象化,因为它可以包含我需要了解并能够调用的自定义方法
当我继续构建层时,我将不得不在堆栈的整个过程中继续这样做。例如,如果我有一个通用抽象控制器或服务层:
public class TestService : Service<TestObject, ITestManager>, ITestService
公共类TestService:Service,ITestService
是否有更好的方法来实现这一点,或者这是允许泛型类调用另一个泛型类的最佳实践?不,您无法回避它。你可以试试,但结果会很糟糕,而且在某种程度上是不正确的。原因是你要求泛型不是泛型,但仍然是泛型 如果一个新类在继承或组合中使用泛型类,并且它本身不知道如何为它正在使用的泛型类指定类型参数,那么它本身必须是泛型的。它类似于方法调用链,其中一个方法可以将参数传递给另一个方法。它不能组成内部方法的参数,而是必须将它们作为调用方的参数,调用方知道它们是什么。类型参数相同 让人感觉像是代码味道的一件事是,您不能使用Manager类型的变量。它必须是完全指定的类型。我提出的一个解决方案是让泛型类实现非泛型接口。这些接口具有尽可能多的泛型类的公共接口(它们不能具有引用类型参数的方法或属性)。然后可以传递接口类型的变量,而不必指定类型参数 例如:
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() {
...
}
}
接口示例{
字符串名称{get;}
void SomeNonGenericMethod(inti);
}
类示例:IExample{
公共字符串名称{get{…}
公共非通用方法(int i){
...
}
公共T SomeGenericMethod(){
...
}
}
似乎您所要做的就是使Manager
可测试,并使用mock作为您可以查询特殊成员的存储库
如果是这样,也许您可以将设计更改为:
public class Manager<T> : IManager<T> {
protected IRepository<T> Repository { get; set; }
// ...
public virtual List<T> GetAll() {
return Repository.GetAll();
}
}
使用Action或Func是否有助于缓解您的问题?这将取决于调用这些函数的时间/原因。对于本例中的存储库,为什么要使用泛型,我有点困惑。如果每次都要实现IRepository,为什么要使用泛型。在您显示的代码中,没有理由需要通用的TInterface。你能解释一下你的rational在这种情况下使用泛型的原因吗?因为它可能是因为你没有说明的原因,但是你可能可以去掉它,从而避免你的错误problem@CraigSuchanec:原因是repository类必须有一个GetAll()方法它返回一个T的列表。这意味着存储库类在T上被参数化了。@siride我知道T在那里,但是TInterface在那里。他没有在集合中使用TInterface。Repository属性的类型为IRepository,但在我的示例中,我的存储库界面如下所示:public interface ITestRepository:IRepository。我还有其他的方法。执行TInterface:IRepository允许我访问IRepository中声明的所有方法,以及ITestRepository界面中声明的任何方法。我有一种感觉,我会被困在这个位置上。我希望能够以某种方式“扩展”抽象存储库属性的实现,使其成为我所需要的类型。我想当我需要调用自定义方法时,我仍然可以将它转换为“ITestRepository”类型,但这几乎和我当前实现它的方式一样难看。我更改了代码,使其看起来像您提供的一样,并运行了单元测试,但它们失败了。Manager类方法正在查看返回IRepository实例的Repository属性。由于未设置该属性,而是设置了“public new ITestRepository Repository”属性,因此它在Manager抽象类中获得了与Repository属性相关的NullReferenceException。很抱歉,我忘记了对子类属性使用
base
。但是不要把我的代码作为一个整体来实现,这只是一个想法。将基添加到存储库调用中可以让一切都完美地工作。不过,这是一个理想的解决方案,因为我必须从Manager的Repository属性中删除抽象修饰符,所以在TestManager级别不强制实现。这很好,因为如果不存在自定义方法,就不需要实现它。
public class TestingManager<T> : Manager<T> {
public new ITestRepository<T> Repository {
get {
return (ITestRepository<T>)base.Repository;
}
set {
base.Repository = value;
}
}
}
[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);
}