You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过多态将多个Repository子类以泛型基类形式传递调用方法?

问题:通过多态批量调用泛型仓储基类的通用方法

我想借助多态将自定义仓储类作为其继承的泛型基类Repository<TEntity>传递,实现对多个不同仓储类统一调用基类中的MethodOne和MethodTwo方法。但当前代码无法运行,因为SomeModelRepository无法转换为Repository<object>,想确认是否有可行方案。

现有代码结构

泛型基仓储类(基于EF上下文)

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
    protected readonly DbContext Context;

    public Repository(DbContext context)
    {
        this.Context = context;
    }

    public IEnumerable<TEntity> MethodOne()
    {
        return Context.Set<TEntity>().DoSomething();
    }

    public IEnumerable<TEntity> MethodTwo()
    {
        // 原有逻辑实现
    }
}

自定义仓储子类示例

internal class SomeModelRepository : Repository<SomeModel>
{
    public __DbContext DbContext
    {
        get { return Context as __DbContext; }
    }

    public SomeModelRepository(__DbContext context) : base(context) { }
}

工作单元类

internal class UnitOfWork : IUnitOfWork
{
    private readonly __DbContext _context;

    public SomeModelRepository SomeModels { get; private set; }
    public SomeOtherModelRepository SomeOtherModels { get; private set; }

    public UnitOfWork(__DbContext context)
    {
        _context = context;
        SomeModels = new SomeModelRepository(context);
        SomeOtherModels = new SomeOtherModelRepository(context);
    }
    // 其他工作单元逻辑
}

客户端代码(无法运行)

public class Client
{
    UnitOfWork _UnitOfWork;

    public Client()
    {
        UnitOfWork _UnitOfWork = new(new __DbContext());
    }

    public void DoSomeClientStuff()
    {
        // 此处报错:无法将SomeModelRepository转换为Repository<object>
        ClientMethod(new List<Repository<object>> { _UnitOfWork.SomeModels, _UnitOfWork.SomeOtherModels }); 
        _UnitOfWork.SaveChanges();
    }

    private void ClientMethod(IEnumerable<Repository<object>> repositories)
    {
        foreach (Repository<object> repository in repositories)
        {
            repository.MethodOne();
            repository.MethodTwo();
        }
    }
}

解决方案:引入非泛型公共接口

C#泛型类是不变的,Repository<SomeModel>不能隐式转换为Repository<object>,即使SomeModel继承自object。要实现多态批量调用,可定义一个非泛型的公共接口,让泛型基仓储类实现该接口。

步骤1:定义非泛型接口

public interface IRepository
{
    IEnumerable MethodOne();
    IEnumerable MethodTwo();
}

步骤2:让泛型基仓储类实现非泛型接口

修改Repository<TEntity>,显式实现非泛型接口方法,复用原有泛型方法的逻辑:

public class Repository<TEntity> : IRepository<TEntity>, IRepository where TEntity : class
{
    protected readonly DbContext Context;

    public Repository(DbContext context)
    {
        this.Context = context;
    }

    // 原有泛型方法
    public IEnumerable<TEntity> MethodOne()
    {
        return Context.Set<TEntity>().DoSomething();
    }

    // 显式实现非泛型接口方法
    IEnumerable IRepository.MethodOne()
    {
        return MethodOne();
    }

    // 原有泛型方法
    public IEnumerable<TEntity> MethodTwo()
    {
        // 原有逻辑实现
    }

    // 显式实现非泛型接口方法
    IEnumerable IRepository.MethodTwo()
    {
        return MethodTwo();
    }
}

步骤3:修改客户端代码

将ClientMethod的参数改为IEnumerable<IRepository>,所有自定义仓储子类都可正常传递:

public class Client
{
    UnitOfWork _UnitOfWork;

    public Client()
    {
        // 修正变量重复定义问题
        _UnitOfWork = new UnitOfWork(new __DbContext());
    }

    public void DoSomeClientStuff()
    {
        ClientMethod(new List<IRepository> { _UnitOfWork.SomeModels, _UnitOfWork.SomeOtherModels }); 
        _UnitOfWork.SaveChanges();
    }

    private void ClientMethod(IEnumerable<IRepository> repositories)
    {
        foreach (var repository in repositories)
        {
            repository.MethodOne();
            repository.MethodTwo();
        }
    }
}

补充说明

如果通用方法不需要返回值,或返回值可统一为非泛型类型,该方案最简洁。若需保留泛型返回值的类型信息,可结合反射或泛型方法遍历,但复杂度会更高。非泛型接口方案在大多数批量调用场景下足够实用。

内容的提问来源于stack exchange,提问作者E. A. Bagby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 14:10:38