C#OOP:在基础混凝土类中使用带有类型参数的接口

时间:2018-08-31 12:19:52

标签: c# oop .net-core

我希望标题能说明问题,我在尝试解决问题时遇到了麻烦。

我正在使用.NET Core 2.1

最近五年来,我在使用Python后刚开始在C#商店工作,所以我的强类型oop有点生锈。这是我所拥有的以及我想做的事情:

一个基本的存储库接口,为数据库实体定义基本的CRUD功能:

public interface IRepository<TEntity, TPrimaryKey> where TEntity : class
{
   TEntity FindById(TPrimaryKey id)
   void Create(TEntity entity);
   void Delete (TEntity entity);
}

我从该接口继承来定义我的存储库类实现的接口:

interface IProductRepository : IRepository<Product, int>
{
   void SomeProductRepoMethod(int someParam);
}

然后我在具体的类中实现所有接口方法:

public class ProductRepository : IProductRepository
{
   public Product FindById(int id)
   {
      // lookup
   }

   public void Create(Product product)
   {
      // save 
   }

   public void SomeProductRepoMethod(int someParam)
   {
      // do product repository specific stuff
   }
   ....
}

现在,我想做的很简单。我想在Create上添加IRepository的重载,它需要IEnumerable的{​​{1}}:

TEntity

但是我想一次定义此重载的实现: 所以我在想可以制作一个抽象的基础存储库类来放置上述实现。我面临的问题是我不确定如何或什至可以用我现在拥有的模型干净地做到这一点。我试图制作一个实现public interface IRepository<TEntity, TPrimaryKey> where TEntity : class ... void Create(IEnumerable<TEntity> entities); ... 的基类,但这意味着 将类型参数传递给基类并传递给接口:

IRepository

然后在我的具体存储库中:

public abstract class BaseRepository<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey>
{
    public abstract TEntity FindById(TPrimaryKey id);

    public abstract void Create(TEntity entity);
    public abstract void Delete(TEntity entity);
    public void Create(IEnumerable<TEntity> entities)
    {
        foreach(TEntity entity in entities)
        {
            Create(entity);
        }
    }
}

这对我来说并不安静,因为我在public class ProductRepository : BaseRepository<Product, int>, IProductRepository { public override Product FindById(int id) { // lookup } public override void Create(Product product) { // save } public void SomeProductRepoMethod(int someParam) { // do product repository specific stuff } .... } IProductRepository中传递了相同类型的参数。我感觉像 我已经接近但不在那儿,我不确定这里的最佳实践方法是什么。如果有人可以建议一种方法,我真的会 感谢您的反馈。很抱歉,这篇文章很长,但我觉得我需要清楚地描述自己想做的事情。谢谢!

2 个答案:

答案 0 :(得分:4)

在接口和抽象类中具有相同类型的参数没什么大不了的。可以使用抽象类解决方案,除非您的ProductRepository需要从其他某个类继承。

实际上,对于您的抽象类,您的IRepository接口不再存在。只需使用BaseRepository处理一切!

解决此问题的另一种方法是扩展方法。在静态类中,您可以这样编写:

public static void Create<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repo, IEnumerable<TEntity> entities) where TEntity : class {
    // do your foreach loop here
} 

现在您可以在任何IRepository实例上调用此方法,如下所示:

repository.Create(...);

答案 1 :(得分:2)

这就是我要做的方式。我会破坏IRepositoryIProductRepository之间的继承关系:

这是您的界面:

public interface IRepository<TEntity, TPrimaryKey> where TEntity : class
{
    TEntity FindById(TPrimaryKey id);
    void Create(TEntity entity);
    void Delete(TEntity entity);
    void Create(IEnumerable<TEntity> entities);
}

internal interface IProductRepository
{
    void SomeProductRepoMethod(int someParam);
}

然后让您的基类像您一样继承IRepository

基类:

public abstract class BaseRepository<TEntity, TPrimaryKey> : 
    IRepository<TEntity, TPrimaryKey> where TEntity : class
{
    public abstract TEntity FindById(TPrimaryKey id);
    public abstract void Create(TEntity entity);
    public abstract void Delete(TEntity entity);

    public void Create(IEnumerable<TEntity> entities)
    {
        foreach (TEntity entity in entities)
        {
            Create(entity);
        }
    }
}

然后派生基类并实现IProductRepository

public class ProductRepository : BaseRepository<Product, int>, IProductRepository
{
    public override Product FindById(int id)
    {
        // find
    }

    public override void Create(Product product)
    {
        // save 
    }

    public void SomeProductRepoMethod(int someParam)
    {
        // do product repository specific stuff
    }

    public override void Delete(Product entity)
    {
        // delete
    }
}

我认为您的派生类对Product存储库的特殊性是BaseRepository上的实现细节。