web-dev-qa-db-fra.com

"Une expression lambda avec un corps d'instruction ne peut pas être convertie en un arbre d'expression"

En utilisant EntityFramework, j'obtiens l'erreur "A lambda expression with a statement body cannot be converted to an expression tree" en essayant de compiler le code suivant:

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

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

Je ne sais pas ce que l'erreur signifie et surtout comment y remédier. De l'aide?

131
pistacchio

objects est-il un contexte de base de données Linq-To-SQL? Dans ce cas, vous ne pouvez utiliser que des expressions simples à droite de l'opérateur =>. La raison en est que ces expressions ne sont pas exécutées, mais sont converties en SQL pour être exécutées sur la base de données . Essayez ceci

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

Vous pouvez utiliser le corps de l'instruction dans l'expression lamba pour IEnumerable collections . Essayez celui-ci:

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

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

Remarquer:
Réfléchissez bien lorsque vous utilisez cette méthode, car ainsi, vous aurez tous les résultats de la requête en mémoire, ce qui peut avoir des effets indésirables sur le reste de votre code.

81
Amir Oveisi

Cela signifie que vous ne pouvez pas utiliser d'expressions lambda avec un "corps d'instruction" (c'est-à-dire des expressions lambda utilisant des accolades) dans les endroits où l'expression lambda doit être convertie en arbre d'expression (ce qui est le cas par exemple avec linq2sql) .

33
sepp2k

Sans en savoir plus sur ce que vous faites (Linq2Objects, Linq2Entities, Linq2Sql?), Cela devrait le rendre efficace:

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

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

Utilisez cette surcharge de select:

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

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

Cela signifie qu'une expression Lambda de type TDelegate qui contient un ([parameters]) => { some code }; ne peut pas être convertie en Expression<TDelegate>. C'est la règle.

Simplifiez votre requête. Celui que vous avez fourni peut être réécrit comme suit et sera compilé:

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

Arr est-il un type de base de Obj? La classe Obj existe-t-elle? Votre code ne fonctionnera que si Arr est un type de base d'Obj. Vous pouvez essayer ceci à la place:

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

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

Les objets de retour LINQ to SQL implémentaient l’interface IQueryable. Ainsi, pour le paramètre de prédicat de la méthode Select, vous ne devez fournir qu'une seule expression lambda sans corps.

Cela est dû au fait que le code LINQ for SQL n'est pas exécuté à l'intérieur du programme, mais plutôt à distance, comme SQL Server ou autres. Ce type d'exécution de chargement paresseux a été obtenu en implémentant IQueryable lorsque son délégué attendu est encapsulé dans la classe de type Expression comme ci-dessous.

Expression<Func<TParam,TResult>>

L'arbre d'expression ne prend pas en charge l'expression lambda avec body et ne prend en charge que l'expression lambda sur une seule ligne, telle que var id = cols.Select( col => col.id );.

Donc, si vous essayez, le code suivant ne fonctionnera pas.

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

Ce qui suit fonctionnera comme prévu.

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

Dans votre cas particulier, le corps sert à créer une variable et le passage à IEnumerable obligera toutes les opérations à être traitées côté client. Je propose la solution suivante.

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

Edit: renommer la convention de codage C #

0
Luke Vo