Come chiamare un metodo di estensione statica non generico con parametri usando Reflection

c# expression-trees reflection

Domanda

Sto usando il codice qui sotto per eseguire i metodi. Funziona con metodi standard di string , ad esempio StartsWith , tuttavia sto tentando di utilizzare diversi metodi di estensione delle stringhe, tra cui una sostituzione per Contains che consente l'insensibilità alle maiuscole / minuscole:

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

L'errore che ricevo è:

Il metodo statico richiede un'istanza nulla, il metodo non statico richiede un'istanza diversa da null.

Come posso risolvere questo?

Per riferimento, ecco l'estensione Contains :

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

Grazie


MODIFICARE

Aggiornato secondo la risposta di Balazs, anche se ora ho il seguente errore:

Espressione di tipo 'System.Linq.Expressions.PropertyExpression' non può essere utilizzata per il parametro di tipo 'System.String' del metodo 'Boolean Contains (System.String, System.String, System.StringComparison)'

Ecco il metodo completo di riferimento:

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

Risposta accettata

È necessario passare una ConsantExpression null come parametro di istanza di Expression.Call e aggiungere m come primo argomento in c .



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché