如何使用Reflection调用带有参数的非泛型静态扩展方法

时间:2012-03-20 11:46:30

标签: c# reflection expression-trees

我使用下面的代码来执行方法。它适用于string的标准方法,例如StartsWith,但是我试图使用几种字符串扩展方法,包括Contains的覆盖,以防止不区分大小写:

var method = "Contains";
var args = new object[] { "@", StringComparison.OrdinalIgnoreCase };

// This works when called
var mi = m.Type.GetMethod(method, args.Select(a => a.GetType()).ToArray());   
if (mi == null) {
    // This does find the method, but causes an error on Expression.Call below
    mi = typeof(Extensions).GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault(meth => meth.Name == method);
}

var c = args.Select(a => Expression.Constant(a, a.GetType()));

return Expression.Lambda<Func<T, bool>>(Expression.Call(m, mi, c), e);

我收到的错误是:

  

静态方法需要null实例,非静态方法需要非null实例。

我该如何解决这个问题?

供参考,以下是Contains扩展名:

public static bool Contains(this string source, string toCheck, StringComparison comp) {
    return source.IndexOf(toCheck, comp) >= 0;
}

由于


修改

根据Balazs的答案进行了更新,但我现在收到以下错误:

  

'System.Linq.Expressions.PropertyExpression'类型的表达式不能用于'Boolean Contains(System.String,System.String,System.StringComparison)'方法'System.String'类型的参数

以下是完整的参考方法:

public static Expression<Func<T, bool>> Build(string member, IEnumerable<object> memberArgs, string method, params object[] args) {
    var e = Expression.Parameter(_type, "e");
    var memberInfo = 
        (MemberInfo) _type.GetField(member) ??
        (MemberInfo) _type.GetProperty(member) ??
        (MemberInfo) _type.GetMethod(member, (memberArgs ?? Enumerable.Empty<object>()).Select(p => p.GetType()).ToArray());
    Expression m;

    if (memberInfo.MemberType == MemberTypes.Method) {
        var a = memberArgs.Select(p => Expression.Constant(p));
        m = Expression.Call(e, (MethodInfo) memberInfo, a);
    }
    else {
        m = Expression.MakeMemberAccess(e, memberInfo);
    }

    var mi = m.Type.GetMethod(method, args.Select(a => a.GetType()).ToArray());
    var c = args.Select(a => Expression.Constant(a, a.GetType()));
    MethodCallExpression call;

    if (mi != null) {
        call = Expression.Call(m, mi, c);
    }
    else {
        mi = typeof(Extensions).GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault(meth => meth.Name == method);
        var newArgsList = c.ToList<object>();
        newArgsList.Insert(0, m);
        c = newArgsList.Select(a => Expression.Constant(a, a.GetType()));
        call = Expression.Call(null, mi, c);
    }

    return Expression.Lambda<Func<T, bool>>(call, e);           
}

1 个答案:

答案 0 :(得分:3)

您必须传递null ConsantExpression作为Expression.Call的实例参数,并添加m作为c中的第一个参数。