Вызов универсального метода с использованием лямбда-выражений (и типа, известного только во время выполнения) - PullRequest
13 голосов
/ 17 мая 2010

Вы можете использовать Объекты лямбда-выражения для представления лямбда-выражения в качестве выражения.

Как создать Объект лямбда-выражения , представляющий общий вызов метода, если вы знаете только тип, который вы используете для универсального сигнатуры метода, во время выполнения?

Например:

Я хочу создать Объекты лямбда-выражения для вызова: public static TSource Last<TSource>( this IEnumerable<TSource> source )

Но я знаю только, что TSource во время выполнения.

Ответы [ 2 ]

26 голосов
/ 17 мая 2010
static Expression<Func<IEnumerable<T>, T>> CreateLambda<T>()
{
    var source = Expression.Parameter(
        typeof(IEnumerable<T>), "source");

    var call = Expression.Call(
        typeof(Enumerable), "Last", new Type[] { typeof(T) }, source);

    return Expression.Lambda<Func<IEnumerable<T>, T>>(call, source)
}

или

static LambdaExpression CreateLambda(Type type)
{
    var source = Expression.Parameter(
        typeof(IEnumerable<>).MakeGenericType(type), "source");

    var call = Expression.Call(
        typeof(Enumerable), "Last", new Type[] { type }, source);

    return Expression.Lambda(call, source)
}
2 голосов
/ 17 мая 2010

Я не до конца понимаю вопрос, но код, который написал dtb, может быть записан просто как:

class MyUtils {
  public static Expression<Func<IEnumerable<T>, T>> CreateLambda<T>() { 
    return source => source.Last();
  }
}

Код в образце от dtb - это почти то же самое, что и компилятор C #, автоматически генерируемый для вас из этого лямбда-выражения (скомпилированного как дерево выражений, потому что тип возвращаемого значения Expression).

Если вы знаете тип во время выполнения, то вы можете использовать решение с помощью dtb или вызвать метод CreateLambda (см. Выше), используя Reflection, который может быть медленнее, но позволяет писать код в лямбда-выражении. в натуральном C #:

var createMeth = typeof(MyUtils).GetMethod("CreateLambda");
LambdaExpression l = createMeth.MakeGenericMethod(yourType).Invoke();

Хорошая вещь в этом подходе состоит в том, что код в CreateLambda может быть намного более сложным, что было бы очень трудно сделать с использованием деревьев выражений явно.

...