如何通过多态将多个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
相关产品推荐
相关产品推荐

