【问题标题】:How to call a non-generic static extension method with parameters using Reflection如何使用反射调用带有参数的非泛型静态扩展方法
【发布时间】:2012-03-20 11:46:29
【问题描述】:

我正在使用下面的代码来执行方法。它适用于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);

我收到的错误是:

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

我该如何解决这个问题?

作为参考,这里是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);           
}

【问题讨论】:

    标签: c# reflection expression-trees


    【解决方案1】:

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

    【讨论】:

    • 我已经尝试过了,但仍然收到错误 - 我已经用完整的方法更新了我的 OP。非常感谢您再次帮助 Balazs :)
    • 您的列表应该是List&lt;Expression&gt;。将m 添加为第一个元素,然后将其他元素添加为AddRange
    • 谢谢你 - 这已经解决了。为了避免我以后再麻烦你,你知道构建表达式树的任何好的参考吗?我似乎无法理解它。
    • 抱歉,我现在什么都不知道。但我找到了this question
    猜你喜欢
    • 2012-11-26
    • 2018-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多