2

I am using the code below to execute methods. It works for standard methods of string , for example StartsWith, however I am attempting to use several string extension methods, including an override for Contains which alllows for case-insensitivity:

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);

The error I receive is:

Static method requires null instance, non-static method requires non-null instance.

How can I solve this?

For reference, here is the Contains extension:

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

Thanks


EDIT

Updated as per Balazs answer, although I now get the following error:

Expression of type 'System.Linq.Expressions.PropertyExpression' cannot be used for parameter of type 'System.String' of method 'Boolean Contains(System.String, System.String, System.StringComparison)'

Here is the full method for reference:

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);           
}
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339

1 Answers1

3

You have to pass a null ConsantExpression as the instance parameter of Expression.Call, and add m as the first argument in c.

Balazs Tihanyi
  • 6,659
  • 5
  • 23
  • 24
  • I have tried this although still receive an error - I have updated my OP with the full method. Many thanks for your help with this yet again Balazs :) – Rory McCrossan Mar 20 '12 at 12:14
  • Your list should be a `List`. Add `m` as the first element, then add the others with `AddRange`. – Balazs Tihanyi Mar 20 '12 at 12:20
  • Thank you - that has fixed it. To save me troubling you again in future, do you know of any good references for building expression trees. I just can't seem to get my head around it. – Rory McCrossan Mar 20 '12 at 12:27
  • 2
    Sorry, I don't know anything right now. But I've found [this question](http://stackoverflow.com/questions/683620/what-is-the-best-resource-for-learning-c-sharp-expression-trees-in-depth). – Balazs Tihanyi Mar 20 '12 at 12:34