当前位置: 首页 > 知识库问答 >
问题:

C#中泛型的接口和继承

景阳曜
2023-03-14

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

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

我想添加一个更具体的 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个答案

邹麻雀
2023-03-14

在某些时候,如果你的标记实体不是真正的抽象,你可能会遇到麻烦。假设您也有命名条目,有些被标记。

现在你有一个 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等。这是你开始怀疑这是否真的是一个好主意的地方;-)

亢仰岳
2023-03-14

您可以继续从< code>IRepository继承

public interface ITaggedRepository<T> : IRepository<T> where T : TaggedEntityBase
{
    IEnumerable<T> ListWithTags(Expression<Func<T, bool>> predicate);
}
 类似资料:
  • 本文向大家介绍C# 泛型接口的抗变和协变,包括了C# 泛型接口的抗变和协变的使用技巧和注意事项,需要的朋友参考一下 1, 泛型接口的协变 如果泛型类型用out关键字标注,泛型接口就是协变的。这也意味着返回类型只能是T。 泛型接口的抗变 如果泛型类型用in关键字标注,泛型接口就是抗变的。这样,接口只能把泛型类型T用作其方法的输入,即方法的参数。 这是泛型接口的抗变和协变的定义,那我们下面来用代码说明

  • 问题内容: 我正在使用具有继承性的流畅接口。我声明基类Constructor受保护,因此您不能创建Foo ,这会导致在调用add()时引发ClassCastException。但是我在返回一个新的Foo实例的静态方法上遇到了麻烦。 这主要是流利的接口,特定领域的语言和泛型方面的一项练习(个人而非家庭作业),所以请不要问我需要什么。 编辑:Eclipse错误 问题答案: 本质上,您有一个递归类型声明

  • 再说起鸭子类型,其实C++和java已经考虑到了,这就是泛型。泛型主要是用来做代码复用的,因为前述它的优点:使得程序员能将注意力从底层细节解放出来,在C++和java体现不是那么明显,因为某些后面会说的原因,细节反而会更多,写起来还麻烦 静态类型语言中每个变量的类型都是固定的,如上一篇末尾所说,要想实现鸭子类型就得结合代码。鸭子类型只需要关注“能做什么”,不关注“是什么”,静态类型语言借助接口,就

  • 问题内容: 我有以下界面: 我在下面有抽象类(没有提到方法插入): 我有具体的课程: 最后,SpecificEntryBean定义为: 我有以下错误: 类型SpecificEntry必须实现继承的抽象方法SingleRecordInterface.insert(AbstractEntryBean) 考虑到SpecificEntryBean扩展了AbstractEntryBean,所以我不明白此错误

  • 为什么叫“泛型模型”,请查看一些基本概念 Keras的泛型模型为Model,即广义的拥有输入和输出的模型,我们使用Model来初始化一个泛型模型 from keras.models import Model from keras.layers import Input, Dense a = Input(shape=(32,)) b = Dense(32)(a) model = Model(inp

  • 问题内容: 我有三节课: 现在在我的主要职能中,我做这样的事情: 但这会产生2个编译时错误: 无法将A转换为fileHandler 无法将B转换为fileHandler 如果基类不是泛型的,那么我如何摆脱这些错误呢? 更新: 我的班级层次结构是: 调用函数的C类或 调用函数的D类。 C和D都从抽象类E派生。 现在,我应该如何在C和D以及E中定义这些功能: 我给出了以下内容: E: C: D: C,