web-dev-qa-db-ja.com

「ステートメント本体を持つラムダ式は、式ツリーに変換できません」

EntityFrameworkを使用すると、次のコードをコンパイルしようとするとエラー「A lambda expression with a statement body cannot be converted to an expression tree」が表示されます。

Obj[] myArray = objects.Select(o =>
{
    var someLocalVar = o.someVar;

    return new Obj() { 
    Var1 = someLocalVar,
    Var2 = o.var2 };
}).ToArray();

エラーが何を意味するのか、何よりもそれを修正する方法がわかりません。助けがありますか?

154
pistacchio

objectsはLinq-To-SQLデータベースコンテキストですか?その場合、=>演算子の右側にある単純な式のみを使用できます。その理由は、これらの式は実行されず、データベースに対して実行されるSQLに変換されるためです。これを試して

Arr[] myArray = objects.Select(o => new Obj() { 
    Var1 = o.someVar,
    Var2 = o.var2 
}).ToArray();
100
Tim Rogers

IEnumerableコレクションのlamba式でステートメント本体を使用できます。これを試してください:

Obj[] myArray = objects.AsEnumerable().Select(o =>
{
    var someLocalVar = o.someVar;

    return new Obj() 
    { 
        Var1 = someLocalVar,
        Var2 = o.var2 
    };
}).ToArray();

注意:
この方法を使用する場合は慎重に検討してください。この方法では、すべてのクエリ結果がメモリに格納され、残りのコードに望ましくない副作用が生じる可能性があるためです。

92
Amir Oveisi

これは、ラムダ式を式ツリーに変換する必要がある場所(たとえば、linq2sqlを使用する場合)で、「ステートメント本体」を持つラムダ式(中括弧を使用するラムダ式)を使用できないことを意味します。 。

36
sepp2k

あなたが何をしているのか(Linq2Objects、Linq2Entities、Linq2Sql?)をもっと知らなくても、これは動作するはずです。

Arr[] myArray = objects.AsEnumerable().Select(o => {
    var someLocalVar = o.someVar;

    return new Obj() { 
        Var1 = someLocalVar,
        Var2 = o.var2 
    }; 
}).ToArray();
5
spender

Selectのこのオーバーロードを使用します。

Obj[] myArray = objects.Select(new Func<Obj,Obj>( o =>
{
    var someLocalVar = o.someVar;

    return new Obj() 
    { 
       Var1 = someLocalVar,
       Var2 = o.var2 
    };
})).ToArray();
3
Mohsen

LINQ to SQL戻りオブジェクトは、IQueryableインターフェイスを実装していました。したがって、Selectメソッドの述語パラメーターには、本体のない単一のラムダ式のみを指定する必要があります。

これは、LINQ for SQLコードは、SQLサーバーなどのリモート側ではなく、プログラム内で実行されるためです。この遅延読み込み実行タイプは、IQueryableを実装することで達成されました。IQueryableの期待デリゲートは、以下のようなExpressionタイプクラスでラップされています。

Expression<Func<TParam,TResult>>

式ツリーは、本体を持つラムダ式をサポートせず、var id = cols.Select( col => col.id );のような単一行のラムダ式のみをサポートします

そのため、次のコードを試しても機能しません。

Expression<Func<int,int>> function = x => {
    return x * 2;
}

以下は期待どおりに機能します。

Expression<Func<int,int>> function = x => x * 2;
2
wajatimur

これは、([parameters]) => { some code };を含むTDelegate型のLambda式はExpression<TDelegate>に変換できないことを意味します。それがルールです。

クエリを簡素化します。指定したものは、次のように書き換えてコンパイルできます。

Arr[] myArray = objects.Select(o => new Obj()
                {
                   Var1 = o.someVar,
                   Var2 = o.var2
                } ).ToArray();
1
smartcaveman

ArrObjの基本型ですか? Objクラスは存在しますか? ArrがObjの基本型である場合にのみ、コードは機能します。代わりにこれを試すことができます:

Obj[] myArray = objects.Select(o =>
{
    var someLocalVar = o.someVar;

    return new Obj() 
    { 
       Var1 = someLocalVar,
       Var2 = o.var2 
    };
}).ToArray();
0
Atanas Korchev

特定の場合、本体は変数を作成するためのものであり、IEnumerableに切り替えると、すべての操作がクライアント側で処理されるようになります。次の解決策を提案します。

Obj[] myArray = objects
.Select(o => new
{
    SomeLocalVar = o.someVar, // You can even use any LINQ statement here
    Info = o,
}).Select(o => new Obj()
{
    Var1 = o.SomeLocalVar,
    Var2 = o.Info.var2,
    Var3 = o.SomeLocalVar.SubValue1,
    Var4 = o.SomeLocalVar.SubValue2,
}).ToArray();

編集:C#コーディング規約の名前を変更

0
Luke Vo