Допустим у меня есть Expression<Func<Foo, Bar>>
calculateBar
, который «уменьшает» в Bar
в Foo
, который я могу использовать так:Есть ли способ более легко сочетать выражения и лямбды?
IQueryable foo = getFoos();
bars = foo.Select(calculateBar);
Но иногда мне нужно, чтобы иметь возможность ссылаться на вход Foo, так что я хочу обернуть calculateBar
так что он может возвращать Tuple<Foo, Bar>
:
public static Expression<Func<TIn, Tuple<TIn, TOut>>> WithInput<TIn, TOut>(
this Expression<Func<TIn, TOut>> expression)
{
var param = Expression.Parameter(typeof(TIn));
var constructor = typeof(Tuple<TIn, TOut>).GetConstructor(new[] { typeof(TIn), typeof(TOut) });
if (constructor == null) throw new ArgumentNullException();
return Expression.Lambda<Func<TIn, Tuple<TIn, TOut>>>(Expression.New(constructor, param, Expression.Invoke(expression, param)), param);
}
Теперь эта функция, на практике, работает отлично. Однако в LINQ-to-Entities конструкторы должны быть без параметров. Поэтому вместо этого я могу создать поддельный Tuple (new WithInput<Foo, Bar> { Input = theFoo, Output = theBar }
), но писать это как выражение будет довольно болезненным.
Есть ли способ построить существующее выражение (без нарушения LINQ-to-Entities), используя Lambda, вместо того чтобы продолжать строить больше Expression
деревьев?
Например (psuedocode):
Expression<Func<Foo, WithInput<Foo, Bar>>> wrapper = foo => new WithInput { Input = foo, Output = Expression.Invoke(calculateBar, foo) };
Brilliant, спасибо, 'MemberInit' велик. –