“Uma expressão lambda com corpo de instrução não pode ser convertida em uma tree de expressão”

Ao usar o EntityFramework , recebo o erro ” A lambda expression with a statement body cannot be converted to an expression tree ” ao tentar compilar o código a seguir:

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

Eu não sei o que o erro significa e, acima de tudo, como corrigi-lo. Qualquer ajuda?

É objects um contexto de database Linq-To-SQL? Nesse caso, você só pode usar expressões simples à direita do operador =>. A razão é que essas expressões não são executadas, mas são convertidas em SQL para serem executadas no database. Tente isso

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

Você pode usar o corpo da instrução na expressão lamba para collections IEnumerable . tente este:

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

Aviso prévio:
Pense cuidadosamente ao usar esse método, pois dessa forma, você terá todos os resultados da consulta na memory, que podem ter efeitos colaterais indesejados no restante do código.

Isso significa que você não pode usar expressões lambda com um “corpo de instrução” (expressões lambda que usam chaves) em locais onde a expressão lambda precisa ser convertida em uma tree de expressão (que é, por exemplo, o caso quando se usa linq2sql) .

Sem saber mais sobre o que você está fazendo (Linq2Objects, Linq2Entities, Linq2Sql?), Isso deve fazer funcionar:

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

Use essa sobrecarga de select:

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

Isso significa que uma expressão Lambda do tipo TDelegate que contém um ([parameters]) => { some code }; não pode ser convertido para uma Expression . É a regra.

Simplifique sua consulta. O que você forneceu pode ser reescrito como o seguinte e irá compilar:

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

Arr é um tipo de base de Obj ? A class Obj existe? Seu código só funcionaria se Arr fosse um tipo base de Obj. Você pode tentar isso:

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

Para o seu caso específico, o corpo é para criar uma variável, e mudar para IEnumerable forçará todas as operações a serem processadas no lado do cliente, proponho a seguinte solução.

 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(); 

Editar: renomear para c # Convenção de codificação

O object de retorno LINQ to SQL estava implementando a interface IQueryable . Portanto, para o parâmetro Select predicate parameter, você deve fornecer apenas uma expressão lambda única sem corpo.

Isso ocorre porque o código LINQ for SQL não é executado dentro do programa, e não no lado remoto, como o SQL Server ou outros. Esse tipo de execução de carregamento lento foi obtido pela implementação do IQueryable, onde o delegate expect está sendo agrupado na class de tipo de Expressão, como a seguir.

 Expression> 

A tree de expressão não suporta expressão lambda com corpo e sua única expressão lambda de linha única de suporte como var id = cols.Select( col => col.id );

Então, se você tentar o seguinte código não funciona.

 Expression> function = x => { return x * 2; } 

O seguinte irá funcionar conforme esperado.

 Expression> function = x => x * 2;