.NET Core中结合继承与泛型的依赖注入问题
解决泛型仓储注入的编译错误问题
这个问题我之前也碰到过,本质是泛型协变导致的——默认情况下C#的泛型接口是不变的,也就是说IRepository<ChildA>和IRepository<BaseChildClass>之间没有继承关系,哪怕ChildA是BaseChildClass的子类,编译器也不会允许你把前者隐式转换成后者。
咱们分两步来解决:
1. 让仓储接口支持协变
修改IRepository<TEntity>接口,在泛型参数前加上out关键字,声明它是协变接口:
public interface IRepository<out TEntity> where TEntity : BaseEntity{}
注意:协变接口的泛型参数只能作为方法的返回值(输出),不能作为方法的输入参数。如果你的
IRepository里有接收TEntity作为参数的方法(比如Add(TEntity entity)),那协变就不适用了,这时候你可能需要换一种注册方式,比如直接注册具体的仓储类型,或者使用工厂模式。
2. 修正服务获取的代码
你在Main方法里最后获取的是BaseChildClass,但实际上你注册的是IRepository<BaseChildClass>,这会导致获取不到服务,需要改成获取对应的接口:
var service = provider.GetService<IRepository<BaseChildClass>>(); // 如果要获取实体实例,你需要在IRepository里添加获取实体的方法,比如Get() // var entity = service?.Get(); // Console.WriteLine(entity?.GetType());
修改后的完整代码
public class BaseEntity{} public class BaseChildClass: BaseEntity{} public class ChildA : BaseChildClass {} public class ChildB : BaseChildClass {} // 支持协变的接口 public interface IRepository<out TEntity> where TEntity : BaseEntity{} public class DataRepository<TEntity> : IRepository<TEntity> where TEntity : BaseEntity{} public class Program { // 模拟配置加载的特性标志 private static bool ChildAFeature = true; public static void Main() { var services = new ServiceCollection(); if (ChildAFeature) { services.AddScoped<IRepository<BaseChildClass>, DataRepository<ChildA>>(); } else { services.AddScoped<IRepository<BaseChildClass>, DataRepository<ChildB>>(); } var provider = services.BuildServiceProvider(); var repository = provider.GetService<IRepository<BaseChildClass>>(); // 输出具体的仓储类型验证结果 Console.WriteLine(repository.GetType()); // 当ChildAFeature为true时,输出:DataRepository`1[ChildA] } }
如果你的IRepository包含输入参数的方法(比如添加实体),协变就用不了,这时候可以考虑用工厂模式来根据条件创建对应的仓储实例,绕过泛型协变的限制:
// 工厂模式示例 services.AddScoped<IRepository<BaseChildClass>>(sp => { if (ChildAFeature) { return new DataRepository<ChildA>(); } else { return new DataRepository<ChildB>(); } });
内容的提问来源于stack exchange,提问作者alvardo
相关产品推荐
相关产品推荐

