如何在BaseRepository基类属性中使用协变派生类作为ILogger泛型参数
实现方案
你可以通过以下两种常用方案实现该需求:
方案1:给基类增加第二个泛型参数(编译时安全,推荐)
给抽象基类新增一个代表派生仓库类型的泛型参数,添加约束保证只能传入继承自当前基类的类型,派生类继承时将自身作为参数传入即可。
// 基类定义 public abstract class BaseRepository<T, TRepository> where TRepository : BaseRepository<T, TRepository> { private readonly ILogger<TRepository> _repositoryLogger; // 构造函数注入对应派生类类型的ILogger protected BaseRepository(ILogger<TRepository> logger) { _repositoryLogger = logger; } } // 派生类实现示例 public class JobSeekerRepository : BaseRepository<JobSeeker, JobSeekerRepository> { public JobSeekerRepository(ILogger<JobSeekerRepository> logger) : base(logger) { } }
该方案特点:
- 完全编译时类型安全,依赖注入容器可直接按泛型规则自动解析,无需额外配置
- 生成的日志默认以派生类为分类,和直接注入
ILogger<JobSeekerRepository>效果完全一致 - 仅存在派生类需要多传一个自身类型参数的微小冗余,适配绝大多数业务场景
方案2:运行时动态生成Logger(无额外泛型参数)
如果你不想修改基类的泛型参数结构,可以通过注入ILoggerFactory,在基类构造函数中读取当前实例的运行时类型动态创建Logger。
public abstract class BaseRepository<T> { private readonly ILogger _repositoryLogger; protected BaseRepository(ILoggerFactory loggerFactory) { // GetType()会返回当前实例的实际运行时类型,也就是对应的派生类类型 _repositoryLogger = loggerFactory.CreateLogger(GetType()); } } // 派生类实现示例 public class JobSeekerRepository : BaseRepository<JobSeeker> { public JobSeekerRepository(ILoggerFactory loggerFactory) : base(loggerFactory) { } }
该方案特点:
- 无需修改基类原有的泛型参数结构,派生类继承写法更简洁
- 运行时生成的Logger功能和泛型
ILogger<Derived>完全一致,日志分类同样为派生类类型 - 缺少编译时的泛型类型校验,仅适合不希望调整基类定义的场景
内容的提问来源于stack exchange,提问作者Mike Lenart
相关产品推荐
相关产品推荐

