如何使用反射将System.Type传递到泛型方法中
本文关键字:泛型方法 Type 何使用 反射 System | 更新日期: 2023-09-27 18:09:13
可能重复:
如何使用反射来调用泛型方法?
我正在尝试简化一些EF代码优先配置。
而不是像这样写代码:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Asset>().ToTable("Assets");
modelBuilder.Entity<VideoAsset>().ToTable("VideoAssets");
modelBuilder.Entity<ImageAsset>().ToTable("ImageAssets");
...
}
我正在将每个类型的表声明封装到一个类中,并使用反射来调用modelBuilder
public class TablePerTypeBuilder<TBase> where TBase : class
{
public void Build(DbModelBuilder modelBuilder)
{
//modelBuilder.Entity<Asset>().ToTable("Assets");
modelBuilder.Entity<TBase>().ToTable(typeof(TBase).Name);
//modelBuilder.Entity<VideoAsset>().ToTable("VideoAssets");
//modelBuilder.Entity<ImageAsset>().ToTable("ImageAssets");
var types = from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetTypes()
where typeof(TBase).IsAssignableFrom(t)
select t;
foreach (Type type in types)
{
modelBuilder.Entity<type>().ToTable(type.Name);
//Error - The type or namespace name 'type' could not be found (are you missing a using directive or an assembly reference?)
}
}
}
由于编译时的安全性,无法将Type添加为泛型参数。那个么,是否可以使用refection进行相同的调用呢?
目的是调用类似的生成器
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
TablePerTypeBuilder<Asset> builder = new TablePerTypeBuilder<Asset>();
builder.Build(modelBuilder);
}
根据建议,您可以使用MakeGenericMethod()
。但像这样的打字有很多难看的地方:
var method = modelBuilder.GetType().GetMethod("Entity");
var genericMethod = method.MakeGenericMethod(type);
var entTypConfig = genericMethod.Invoke(modelBuilder, null);
entTypConfig.GetType()
.InvokeMember("ToTable", BindingFlags.InvokeMethod, null, entTypConfig,
new object[] {type.Name});
您可以构建一个表达式并将其编译为委托:
public void Build(DbModelBuilder builder)
{
// Stuff
var param = Expression.Parameter(typeof(DbModelBuilder));
foreach (var type in types)
{
var method = Expression.Call(
Expression.Constant(this), // Call to self.
"BuildInternal", // The method to call.
new[] { type }, // The generic arguments.
param); // The parameters.
Expression.Lambda(method, param).Compile().DynamicInvoke(builder);
}
}
执行时可以调用:
public void BuildInternal<T>(DbModelBuilder builder) where T : class
{
builder.Entity<T>.ToTable(typeof(T).Name);
}