通过反射访问/执行通用方法?

时间:2016-05-27 20:03:46

标签: c# entity-framework generics reflection

我正在尝试在使用EF6时动态切换我的表注释的架构值@ Runtime。

所以这就是我到目前为止所得到的:

var builder = new DbModelBuilder()
var dbSetProperties = typeof(T).GetProperties().Where(p => p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>));

foreach (PropertyInfo property in dbSetProperties)
{
    Type[] propTypes = property.PropertyType.GetGenericArguments();

    // Iterate the DbSets and set the correct schema
    foreach (Type dbSetType in propTypes)
    {
        // Get the TableAttribute
        var tableAttribute = Attribute.GetCustomAttribute(dbSetType, typeof(TableAttribute));

        MethodInfo dbModelMethodInfo = typeof(DbModelBuilder).GetMethod("Entity");
        MethodInfo entityTypeConfigMethodInfo = typeof(EntityTypeConfiguration<>).GetMethod("ToTable", new[] { typeof(String), typeof(String) });
        MethodInfo genericDbModelMethodInfo = dbModelMethodInfo.MakeGenericMethod(dbSetType);

        genericDbModelMethodInfo.Invoke(builder, null);
        entityTypeConfigMethodInfo.Invoke(genericDbModelMethodInfo, new Object[] { (tableAttribute as TableAttribute).Name, "NEW_SCHEMA_VALUE" });
    }
}

我想要完成的是这样的事情(不起作用):

builder.Entity<dbSetType>().ToTable((tableAttribute as TableAttribute).Name, "NEW_SCHEMA_VALUE");

基本上,对于T我想拉取DbSets,确定实体中使用的类&lt;&gt; generic,获取TableAttribute,并将Schema设置为新值。

目前,在entityTypeConfigMethodInfo.Invoke上,我收到的错误是“无法对ContainsGenericParameters为true的类型或方法执行后期绑定操作”。

我错过了什么?

3 个答案:

答案 0 :(得分:3)

嗯,是的,你期待什么?

你说你在这一行得到错误:

entityTypeConfigMethodInfo.Invoke(genericDbModelMethodInfo, new Object[] { (tableAttribute as TableAttribute).Name, "NEW_SCHEMA_VALUE" });

问题不在于这一行,而在于这一行:

MethodInfo entityTypeConfigMethodInfo = typeof(EntityTypeConfiguration<>).GetMethod("ToTable", new[] { typeof(String), typeof(String) });

你得到的方法ToTable 类型?

包含该方法的类型仍然是开放的泛型类型。您必须指定类型参数以使其成为特定类型,然后您可以获取要调用的方法。

换句话说,你需要这个:

MethodInfo entityTypeConfigMethodInfo =
    typeof(EntityTypeConfiguration<>).MakeGenericType(...).GetMethod("ToTable", new[] { typeof(String), typeof(String) });
                                     ^-------------------^

答案 1 :(得分:1)

要为第二次调用获取正确的封闭泛型methodinfo,请将代码重写为:

MethodInfo genericDbModelMethodInfo = dbModelMethodInfo.MakeGenericMethod(dbSetType);
MethodInfo entityTypeConfigMethodInfo = genericDbModelMethodInfo.ReturnType.GetMethod("ToTable", new[] { typeof(String), typeof(String) });

然后你必须使用genericDbModelMethodInfo.Invoke调用的返回值作为第二个调用中的第一个参数。

var obj = genericDbModelMethodInfo.Invoke(builder, null);
entityTypeConfigMethodInfo.Invoke(obj, new Object[] { (tableAttribute as TableAttribute).Name, "NEW_SCHEMA_VALUE" });

这是因为MethodInfo.Invoke中的第一个参数是您要调用该方法的对象。

答案 2 :(得分:0)

由于EntityTypeConfiguration是通用类型,您是否可以指定对象中用于 EntityTypeConfiguration 的Generic参数的类型。 例如:

 Type type= typeof (GenericClass<>).MakeGenericType(typeof(int));

这里'GenericClass'是一个具有通用'T'参数的泛型类。    我在获取它的类型信息时指定了 int type 。 然后调用此类型的方法将正常工作。

我编写了一个示例代码,该代码执行相同的操作,但最低限度的是您尝试执行的操作,可能有助于您解决错误。

 class Program
{
    static void Main()
    {

        Type type= typeof (GenericClass<>).MakeGenericType(typeof(int));

        var method = type.GetMethod("TestMethod");

        var instance = Activator.CreateInstance(type);


        method.Invoke(instance, null); 

    }
}

public class GenericClass<T> where T : struct // These parameters can be anything
{
    public T TestMethod()
    {
        T a = new T();

        return a; 
    }
}