繁体   English   中英

通过反射将参数传递给函数

[英]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> 

两者都返回一个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 });
}

我此时的假设是:

  1. 您要传递实体的类型(与配置相反)。 如果您要传递配置类的类型,则将参数名称entityType更改为entityConfigType并删除构成泛型类型的第一行。 请参阅下面的类型检查代码,该代码应替换第一行。
  2. 您的扩展方法位于名为Extensions的类中。
  3. 您正在检查类型是否符合AddConfiguration(...)的要求,因此您不会因使用错误类型而获得调用异常。 再次参见下面的类型检查示例,我通常会添加到这种非泛型方法中。
  4. 设置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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM