通过反射传递参数给函数
Pass parameter to function via reflection
我有一个具有以下签名的扩展方法
public static void AddConfiguration<TEntity>(this ModelBuilder builder, EntityTypeConfiguration<TEntity> configuration)
where TEntity : class
{
...
}
我想通过反射传递参数,试过这个方法:
var ctors = type.GetConstructors(BindingFlags.Public);
modelBuilder.AddConfiguration(ctors[0].Invoke(new object[] { }));
这样:
modelBuilder.AddConfiguration(Activator.CreateInstance(type));
我从反射中得到的类是这样的:
public class LessonMapping : EntityTypeConfiguration<Lesson>
public class ChapterMapping : EntityTypeConfiguration<Chapter>
public class TrainingMapping : EntityTypeConfiguration<Training>
return 和 object
两者,因此该方法不接受它们。有什么办法吗?
Activator
有一个通用方法,用于创建具有默认构造函数的类型化实例。看起来你已经有了,所以使用以下内容:
var obj = Activator.CreateInstance<LessonMapping>();
modelBuilder.AddConfiguration(obj);
如果这对您不起作用或者您需要将参数传递给构造函数:
var obj = (LessonMapping)Activator.CreateInstance(typeof(LessonMapping));
modelBuilder.AddConfiguration(obj);
最后,如果您将此代码放入另一个通用方法中,您将用通用方法替换 LessonMapping 等:
void DoSomethingGeneric<TEntity>(ModelBuilder builder)
{
var obj = Activator.CreateInstance<EntityTypeConfiguration<TEntity>>();
modelBuilder.AddConfiguration(obj);
}
编辑 添加 AddConfiguration 方法的反射
对于 AddConfiguration 方法的非泛型用法,您必须使用反射来调用它:
void DoSomethingNonGeneric(ModelBuilder builder, Type entityType)
{
// make the generic type for the given entity type using the generic definition
var entityConfigType = typeof(EntityTypeConfiguration<>).MakeGenericType(new Type[] { entityType });
// instantiate the entity type configuration
var obj = Activator.CreateInstance(entityConfigType);
// get and make a generic method to invoke with the object above. Check the binding flags if it doesn't find the method
var methodDef = typeof(Extensions).GetMethod("AddConfiguration", BindingFlags.Static | BindingFlags.Public);
var method = methodDef.MakeGenericMethod(new Type[] { entityConfigType });
// and finally the end goal
method.Invoke(null, new object[] { builder, obj });
}
此时我的假设是:
- 您想要传递实体的类型(而不是配置)。如果要传递配置类型 classes,则将参数名称
entityType
更改为 entityConfigType
并删除构成通用类型的第一行。请参阅下面的类型检查代码,该代码应替换第一行。
- 您的扩展方法在名为
Extensions
的 class 中。
- 您正在检查的类型是否符合
AddConfiguration(...)
的要求,这样您就不会因为使用了错误的类型而导致调用异常。再次查看下面的类型检查示例,我通常会添加到此类非泛型方法中。
- 设置
methodDef
的行按预期工作,因为我目前没有办法对其进行测试。
如果您直接传递 entityConfigType
并想检查类型,请在前几行中添加:
if (!CheckDerivesFrom(typeof(EntityTypeConfiguration<>), entityConfigType)
throw new ArgumentException("entityConfigType");
并在某处创建检查方法。我确信必须有一种更简单的方法来测试一个类型是否派生自给定的通用定义,但我一直使用它,直到我看到更简单的方法。
bool CheckDerivesFrom(Type baseType, Type typeToCheck)
{
if (!baseType.IsGenericDefinition)
return baseType.IsAssignableFrom(typeToCheck);
// assume typeToCheck is never a generic definition
while (typeToCheck != null && typeToCheck != typeof(object))
{
if (typeToCheck.IsGenericType && baseType.IsAssignableFrom(typeToCheck.GetGenericDefinition()))
return true;
typeToCheck = typeToCheck.BaseType;
}
return false;
}
我有一个具有以下签名的扩展方法
public static void AddConfiguration<TEntity>(this ModelBuilder builder, EntityTypeConfiguration<TEntity> configuration)
where TEntity : class
{
...
}
我想通过反射传递参数,试过这个方法:
var ctors = type.GetConstructors(BindingFlags.Public);
modelBuilder.AddConfiguration(ctors[0].Invoke(new object[] { }));
这样:
modelBuilder.AddConfiguration(Activator.CreateInstance(type));
我从反射中得到的类是这样的:
public class LessonMapping : EntityTypeConfiguration<Lesson>
public class ChapterMapping : EntityTypeConfiguration<Chapter>
public class TrainingMapping : EntityTypeConfiguration<Training>
return 和 object
两者,因此该方法不接受它们。有什么办法吗?
Activator
有一个通用方法,用于创建具有默认构造函数的类型化实例。看起来你已经有了,所以使用以下内容:
var obj = Activator.CreateInstance<LessonMapping>();
modelBuilder.AddConfiguration(obj);
如果这对您不起作用或者您需要将参数传递给构造函数:
var obj = (LessonMapping)Activator.CreateInstance(typeof(LessonMapping));
modelBuilder.AddConfiguration(obj);
最后,如果您将此代码放入另一个通用方法中,您将用通用方法替换 LessonMapping 等:
void DoSomethingGeneric<TEntity>(ModelBuilder builder)
{
var obj = Activator.CreateInstance<EntityTypeConfiguration<TEntity>>();
modelBuilder.AddConfiguration(obj);
}
编辑 添加 AddConfiguration 方法的反射
对于 AddConfiguration 方法的非泛型用法,您必须使用反射来调用它:
void DoSomethingNonGeneric(ModelBuilder builder, Type entityType)
{
// make the generic type for the given entity type using the generic definition
var entityConfigType = typeof(EntityTypeConfiguration<>).MakeGenericType(new Type[] { entityType });
// instantiate the entity type configuration
var obj = Activator.CreateInstance(entityConfigType);
// get and make a generic method to invoke with the object above. Check the binding flags if it doesn't find the method
var methodDef = typeof(Extensions).GetMethod("AddConfiguration", BindingFlags.Static | BindingFlags.Public);
var method = methodDef.MakeGenericMethod(new Type[] { entityConfigType });
// and finally the end goal
method.Invoke(null, new object[] { builder, obj });
}
此时我的假设是:
- 您想要传递实体的类型(而不是配置)。如果要传递配置类型 classes,则将参数名称
entityType
更改为entityConfigType
并删除构成通用类型的第一行。请参阅下面的类型检查代码,该代码应替换第一行。 - 您的扩展方法在名为
Extensions
的 class 中。 - 您正在检查的类型是否符合
AddConfiguration(...)
的要求,这样您就不会因为使用了错误的类型而导致调用异常。再次查看下面的类型检查示例,我通常会添加到此类非泛型方法中。 - 设置
methodDef
的行按预期工作,因为我目前没有办法对其进行测试。
如果您直接传递 entityConfigType
并想检查类型,请在前几行中添加:
if (!CheckDerivesFrom(typeof(EntityTypeConfiguration<>), entityConfigType)
throw new ArgumentException("entityConfigType");
并在某处创建检查方法。我确信必须有一种更简单的方法来测试一个类型是否派生自给定的通用定义,但我一直使用它,直到我看到更简单的方法。
bool CheckDerivesFrom(Type baseType, Type typeToCheck)
{
if (!baseType.IsGenericDefinition)
return baseType.IsAssignableFrom(typeToCheck);
// assume typeToCheck is never a generic definition
while (typeToCheck != null && typeToCheck != typeof(object))
{
if (typeToCheck.IsGenericType && baseType.IsAssignableFrom(typeToCheck.GetGenericDefinition()))
return true;
typeToCheck = typeToCheck.BaseType;
}
return false;
}