C#中使用泛型的接口和继承

时间:2017-02-08 18:04:25

标签: c# generics inheritance

为了在.NET Core中使用依赖注入,我们为控制器构建了一堆存储库接口,用于数据库交互。

我们有一个EntityBase类,其中包含一些方法,我们的通用存储库接口使用该基类,如:IRepository<T> where T : EntityBase

我想添加一个更具体的TaggedEntityBase类,其扩展EntityBase来表示我们有一些实体,我们希望按标签过滤这些实体。我希望TaggedEntityBase有一个我可以在我的控制器中使用的抽象属性,这样我就可以抽象出来并重用过滤方法。

所以我想要的是这样的,但我想我希望ITaggedRepository也从IRepository继承,以便实现ITaggedRepository的类保证ListAll方法和ListWithTags方法:

public class EntityBase { }

public abstract class TaggedEntityBase : EntityBase
{
    public string TagIDs { get; }
}


public interface IRepository<T> where T : EntityBase 
{
    IEnumerable<T> ListAll();
}

public interface ITaggedRepository<T> where T : TaggedEntityBase
{
    IEnumerable<T> ListWithTags(System.Linq.Expressions.Expression<Func<T, bool>> predicate);
}

我相当肯定我只是通过追求这种思路而彻底迷惑自己,但我不确定如何做我真正想要的事情。我知道我需要为依赖注入保留抽象的东西,但我觉得我正在接近界面的可能性。

有没有更好的思路可以让我到达我想去的地方?

2 个答案:

答案 0 :(得分:2)

您可以继续并继承IRepository<T>

public interface ITaggedRepository<T> : IRepository<T> where T : TaggedEntityBase
{
    IEnumerable<T> ListWithTags(Expression<Func<T, bool>> predicate);
}

答案 1 :(得分:2)

如果你的TaggedEntity不是真正的抽象,你可能会遇到麻烦。假设你有NamedEntities,有些是Tagged。

现在你有一个INamedRepository,ITaggedRepository和一个INamedTaggedRepository(你的基础实体会遇到类似的问题)。

你可以做类似的事情:

public class EntityBase {}

public interface ITagged
{
    string TagIDs { get; }
}

public interface INamed
{
    string Name { get; }
}

public class Book : EntityBase, ITagged, INamed
{
    public string TagIDs { get; set; }
    public string Name { get; }
}

public interface IRepository<T> where T : EntityBase
{
    IEnumerable<T> ListAll();
}

public interface IQueryTags<T> where T : ITagged
{
    IEnumerable<T> ListWithTags(Expression<Func<T, bool>> predicate);
}

public interface IQueryByName<T> where T : INamed
{
    T GetByName(string name);
}

public interface IBookRepository : IRepository<Book>, IQueryTags<Book>, IQueryByName<Book>
{

}

public class ConcreteBookRepository: IBookRepository
{
    public IEnumerable<Book> ListAll()
    {
        throw new NotImplementedException();
    }

    public IEnumerable<Book> ListWithTags(Expression<Func<Book, bool>> predicate)
    {
        throw new NotImplementedException();
    }

    public Book GetByName(string name)
    {
        throw new NotImplementedException();
    }
}

在具体实现中,您可以通过合成使用ByNameQueryer,TagQueryer和一些具体的存储库。

我不太喜欢通用存储库,所以我倾向于将IRepository重命名为IStore,因为它通常只包含CRUD方面。

哦,然后一些实体你无法删除,有些无法更新。你最终会把它分解为IAdd,IUpdate,IDelete等。这就是你开始想知道这是否也是一个好主意; - )