2016-08-03 6 views
1

のは、私はそうのように使用することができますFooBarを、「減らす」Expression<Func<Foo, Bar>>calculateBarを持っているとしましょうそう、それはTuple<Foo, Bar>を返すことができるcalculateBarをラップする:式とラムダを簡単に組み合わせる方法はありますか?</p> <pre><code>IQueryable foo = getFoos(); bars = foo.Select(calculateBar); </code></pre> <p>はしかし、私は時々、入力のFooを参照できるようにする必要がありますので、私はしたい:

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では、コンストラクタはパラメータなしでなければなりません。その代わりに、私は擬似タプル(new WithInput<Foo, Bar> { Input = theFoo, Output = theBar })を作成したいかもしれませんが、式として書くことはむしろ苦痛になるでしょう。

Expressionツリーを引き続き作成する代わりに、Lambdaを使用して既存の式(LINQ-to-Entitiesを怒らせることなく)を構築する方法はありますか?例えば

(擬似コード):

Expression<Func<Foo, WithInput<Foo, Bar>>> wrapper = foo => new WithInput { Input = foo, Output = Expression.Invoke(calculateBar, foo) }; 

答えて

1

MemberInit式を書くには、あなたがTupleのために何をしたかと比べてそれほど苦痛ではありません。記録のために、これは次のようなものになります。

public static Expression<Func<TIn, WithInput<TIn, TOut>>> WithInput<TIn, TOut>(
    this Expression<Func<TIn, TOut>> expression) 
{ 
    var parameter = expression.Parameters[0]; 
    var resultType = typeof(WithInput<TIn, TOut>); 
    var body = Expression.MemberInit(Expression.New(resultType), 
     Expression.Bind(resultType.GetProperty("Input"), parameter), 
     Expression.Bind(resultType.GetProperty("Output"), expression.Body)); 
    return Expression.Lambda<Func<TIn, WithInput<TIn, TOut>>>(body, parameter); 
} 

今、主題についてです。カスタム表現処理ユーティリティライブラリ(あなた自身または第三者)を使用せずに、既存のラムダに基づいて式を構築することはできません。例えば

LINQKitこのように使用することができるInvokeExpand拡張方法を提供する:

using LinqKit; 

public static Expression<Func<TIn, WithInput<TIn, TOut>>> WithInput<TIn, TOut>(
    this Expression<Func<TIn, TOut>> expression) 
{ 
    return Linq.Expr((TIn input) => new WithInput<TIn, TOut> 
    { 
     Input = input, 
     Output = expression.Invoke(input) 
    }).Expand(); 
} 
+0

ブリリアント、おかげで、 'MemberInit'が大きいです。 –

関連する問題

 関連する問題