如何为类型设置约束,使其必须是另一种泛型类型

时间:2014-11-15 14:22:54

标签: c# generics inheritance

这可能是之前提出的,但我无法解决这个问题。也许如果我能得到正确的头衔,我可以贬低它。

我有这个通用存储库接口:

public interface IRepository<TEntity>
{
    TEntity Resolve<TEntity>(); // dummy function, just to get the idea
}

我还有一个通用的工作单元,它能够解析通用存储库:

public interface IUnitOfWork
{
    IRepository<TEntity> GetGenericRepository<TEntity>() where TEntity : class;
}

到目前为止一切顺利。

但是随着现实生活的继续,我想创建一个自定义存储库,其中包含一些特定的功能。所以我在想:继承;像这样:

public class SpecialRepository : IRepository<SomeEntityType>
{
    public void SomeSpecialFunction() { };
}

显然,使用GetGenericRepository方法无法解析此类型,所以我想:让我们为IUnitOfWork接口添加一个额外的方法:

public interface IUnitOfWork
{
    //same old get generic repository
    IRepository<TEntity> GetGenericRepository<TEntity>() where TEntity : class;

    //the newly added.
    T GetInheretedRepository<T>() where T : class;
}

我希望能够使用特殊存储库调用工作单元,如下所示:

public test()
{
    IUnitOfWork uow = new UnitOfWork();

    //I want to make this call with a constraint on TemplateRepo
    //to enforce it's type: IRepository<T> (which TemplateRepo is)
    var y = uow.GetInheretedRepository<TemplateRepo>(); 
}

问题是:如何将T中的T GetInheretedRepository<T>() where T : class;类型限制为类型:IRepository<TEntity>

我试过了:

public interface IUnitOfWork
{  
    //the newly added.
    //error: Only class or interface could be specified as constraint
    T GetInheretedRepository<T>() where T : class, IRepository;     }

public interface IUnitOfWork
{  
    //the newly added.
    //error: type argument missing
    T GetInheretedRepository<T>() where T : class, IRepository<>; 
}

不起作用。

我可以放弃约束作为快速修复或者可能创建一个继承的工作单元,但随后;问题仍然存在。

2 个答案:

答案 0 :(得分:2)

执行此操作的方法是添加第二个泛型类型参数,如下所示:

TRepository GetInheretedRepository<TRepository, TEntity>() 
    where TRepository : IRepository<TEntity>
    where TEntity : class;

这里提供存储库类型和实体类型。这样C#编译器就可以检查类型是否匹配。以下是如何调用它:

var rep = uow.GetInheretedRepository<SpecialRepository, SomeEntityType>();

rep.SomeSpecialFunction();

这显然很糟糕,因为你必须指定这两种类型。但更重要的是,这很糟糕,因为您必须指定具体类型,使您的代码依赖于具体类型;违反了Dependency Inversion Principle

我真的想建议您远离一个依赖于具体类型的设计,甚至更好,远离那些在特定存储库类上有许多方法的设计,因为这违反了{{{ 3}},SRPOCP这可能会在以后导致维护问题。

相反,请查看ISP中描述的应用程序设计。

答案 1 :(得分:1)

您需要指定第二个类型

public interface IUnitOfWork
{  
    //the newly added.
    T GetInheretedRepository<T, TEntity>() where T : class, IRepository<TEntity>; 
}

public interface IRepository<TEntity>
{
    TEntity Resolve(); // dummy function, just to get the idea
}

编译好的示例 - https://dotnetfiddle.net/MmmPil