通过反射调用Expression的泛型方法

时间:2016-11-22 08:42:00

标签: c# entity-framework generics reflection

我有一个泛型方法,它应该从表中返回最后一条记录:

public T FindLast<TKey>(Expression<Func<T,TKey>> specification = null)
{
    return specification == null
        ? Set().LastOrDefault()
        : Set().OrderBy(specification).LastOrDefault();
}

我需要通过反思来调用它

var methodCreateReadRepositoryAttr = (entityMetadata.GetEntityAttributeType() != null) ? 
typeof(IRepositoryFactory).GetMethod("CreateReadRepository").MakeGenericMethod(entityMetadata.GetEntityAttributeType()) : null;

var methodEntityGet3 = attributeReadRepository.GetType().GetMethod("FindLast", new Type[] { typeof(Expression<Func<ArticleAttribute,int>>) });

但是在调试methodEntityGet3中为null。我做错了什么?

2 个答案:

答案 0 :(得分:1)

问题是您正在请求一个封闭类型的方法,同时方法FindLast是通用的并且具有开放类型,即参数的类型是Expression<Func<T, TKey>>而不是类型你提供。反射系统不会去创建最适合的通用方法,因为这可能取决于语言中的规则。您可以实现将参数转换为dynamic,但我并不完全确定。

此外,没有简单的方法来获取类型参数TTKey,因此我建议您仅使用其名称搜索方法,然后显式创建下面的泛型方法,就像您一样为上述方法做了。

编辑:实际上,dynamic解决方案实际上可行,并且可能比任何反射调用都更具可读性。以下代码编译并输出可预期的内容:

class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo<string>();
        Expression<Func<string, int>> arg = s => s.Length;
        CallFindLast(foo, arg);
        Console.Read();
    }

    private static void CallFindLast(Foo<string> foo, object arg)
    {
        var dynamicArg = (dynamic)arg;
        foo.FindLast(dynamicArg);
    }

    private class Foo<T>
    {
        public T FindLast<TKey>(Expression<Func<T, TKey>> specification = null)
        {
            Console.WriteLine($"T: {typeof(T).Name}, TKey: {typeof(TKey).Name}");
            return default(T);
        }
    }
}

答案 1 :(得分:0)

你需要打破你的方法来调用两个:

var methodEntityGet3 = attributeReadRepository.GetType().GetMethod("FindLast");
var closedGenericMethod = methodEntity3.MakeGenericMethod(new Type[] { typeof(Expression<Func<ArticleAttribute,int>>) };