簡體   English   中英

“帶有語句體的 lambda 表達式無法轉換為表達式樹”

[英]"A lambda expression with a statement body cannot be converted to an expression tree"

在使用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();

我不知道錯誤是什么意思,最重要的是如何解決它。 有什么幫助嗎?

objects是 Linq-To-SQL 數據庫上下文嗎? 在這種情況下,您只能使用 => 運算符右側的簡單表達式。 原因是,這些表達式沒有執行,而是轉換為 SQL 以對數據庫執行。 嘗試這個

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

您可以在IEnumerable collections 的 Lamba 表達式中使用語句體。 試試這個:

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

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

注意:
使用此方法時請仔細考慮,因為這樣一來,您將在應用程序的 memory 中獲得所有查詢結果,這可能會對您的代碼的 rest 產生不必要的副作用。

It means that you can't use lambda expressions with a "statement body" (ie lambda expressions which use curly braces) in places where the lambda expression needs to be converted to an expression tree (which is for example the case when using linq2sql) .

在不知道更多關於你在做什么(Linq2Objects、Linq2Entities、Linq2Sql?)的情況下,這應該使它工作:

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

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

LINQ 到 SQL 返回 object 正在實現IQueryable接口。 因此,對於Select方法謂詞參數,您應該只提供沒有正文的單個 lambda 表達式。

這是因為 SQL 代碼的 LINQ 代碼不在程序內部執行,而不是在遠程端(如 SQL 服務器或其他)執行。 這種延遲加載執行類型是通過實現 IQueryable 實現的,其中它的期望委托被包裝在表達式類型 class 中,如下所示。

Expression<Func<TParam,TResult>>

表達式樹不支持帶正文的 lambda 表達式,它僅支持單行 lambda 表達式,例如var id = cols.Select( col => col.id );

因此,如果您嘗試以下代碼將無法正常工作。

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

以下將按預期工作。

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

使用 select 的這個重載:

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

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

參加聚會已經晚了 9 年,但是對您的問題采取了不同的方法(沒有人提到過?):

語句體適用於Func<>但不適用於Expression<Func<>> IQueryable.Select想要一個Expression<> ,因為它們可以翻譯為實體框架 - Func<>不能。

因此,您要么使用AsEnumerable並開始使用 memory 中的數據(不推薦,如果不是真的必要),或者繼續使用推薦的IQueryable<> 有一種叫做linq query的東西,它使一些事情變得更容易:

IQueryable<Obj> result = from o in objects
                         let someLocalVar = o.someVar
                         select new Obj
                         {
                           Var1 = someLocalVar,
                           Var2 = o.var2
                         };

使用let您可以定義一個變量並在select (或where ,...)中使用它 - 並且您繼續使用IQueryable直到您真正需要執行並獲取對象。

之后你可以Obj[] myArray = result.ToArray()

這意味着 TDelegate 類型的TDelegate表達式包含([parameters]) => { some code }; 無法轉換為Expression<TDelegate> 這是規矩。

簡化您的查詢。 您提供的可以重寫為以下內容並將編譯:

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

對於您的特定情況,主體用於創建變量,切換到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# 編碼約定

ArrObj的基本類型嗎? Obj class 是否存在? 僅當 Arr 是 Obj 的基本類型時,您的代碼才有效。 你可以試試這個:

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

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

如其他回復所述,您只能在=>運算符右側使用簡單表達式。 我建議使用這個解決方案,它包括創建一個方法來執行您想要在 lambda 內部執行的操作:

public void SomeConfiguration() {
    // ...
    Obj[] myArray = objects.Select(o => Method()).ToArray();
    // ..
}

public Obj Method() {
    var someLocalVar = o.someVar;

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

Al ser una Consulta a la base de datos, LINQ no puede convertir una operation Lambda multilínea, ya que el compilador no sabe como convertir la multilinea en lenguaje TRANSACT SQL。

Como un resultado esperado en una operation LINQ Lambda de base de datos,se espera una devolución de una sola linea。

Si es不可缺少的實現 una función lambda compleja, obtenga todos los resultados en un List o un Enumerable, y sobre ese resultado ahora si realice la opación multilínea。

Ejemplo con uso de ToArray() o en su caso, ToList():

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

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

}).ToArray();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM