C#如何在父类中传入子类作为泛型类型
问题
开发中使用某第三方库,该库提供的类要求将实例化它的当前类作为泛型参数传入。现有继承自DbContext的BaseContext类,其OnModelCreating方法中实例化了SqliteDropCreateDatabaseWhenModelChanges<BaseContext>并设置为数据库初始化器。
现在希望继承BaseContext类,但不想重写OnModelCreating方法,却不知如何让父类中的泛型参数自动使用子类类型。尝试用typeof(this)作为泛型参数,此方法无效。
示例代码:
public class BaseContext : DbContext { public BaseContext(string connectionString) : base(connectionstring) { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // 此处 var sqliteConnectionInitializer = new SqliteDropCreateDatabaseWhenModelChanges<BaseContext>(modelBuilder); Database.SetInitializer(sqliteConnectionInitializer); } }
尝试的无效代码:
var sqliteConnectionInitializer = new SqliteDropCreateDatabaseWhenModelChanges<typeof(this)>(modelBuilder);
解决方案
方案一:使用奇异递归模板模式(CRTP)
这是最简便且性能最优的编译时解决方案,通过泛型基类让子类自动传入自身类型。
修改后的基类代码:
public class BaseContext<TContext> : DbContext where TContext : BaseContext<TContext> { public BaseContext(string connectionString) : base(connectionString) { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { var sqliteConnectionInitializer = new SqliteDropCreateDatabaseWhenModelChanges<TContext>(modelBuilder); Database.SetInitializer(sqliteConnectionInitializer); } }
子类继承时只需将自身作为泛型参数传入:
public class MyDerivedContext : BaseContext<MyDerivedContext> { public MyDerivedContext(string connectionString) : base(connectionString) { } // 无需重写OnModelCreating方法 }
原理:通过泛型约束where TContext : BaseContext<TContext>确保传入的类型是当前基类的子类,编译时TContext会被替换为子类的实际类型,从而让父类自动使用子类作为泛型参数初始化第三方库类。
方案二:反射动态实例化(无需修改基类泛型结构)
如果无法修改基类的泛型定义,可以通过反射在运行时动态获取当前实例的子类类型:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { // 获取当前实例的实际类型(子类类型) var contextType = this.GetType(); // 构造泛型版本的初始化器类型 var initializerGenericType = typeof(SqliteDropCreateDatabaseWhenModelChanges<>).MakeGenericType(contextType); // 动态创建实例 var initializer = Activator.CreateInstance(initializerGenericType, modelBuilder); // 设置数据库初始化器 Database.SetInitializer(initializer as IDatabaseInitializer<DbContext>); }
此方案无需调整基类结构,但因为是运行时反射操作,性能略逊于编译时确定的泛型方案,适合无法修改基类的场景。
内容的提问来源于stack exchange,提问作者emilaz
相关产品推荐
相关产品推荐

