“带有语句主体的lambda表达式无法转换为表达式树”


181

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

我不知道该错误意味着什么,最不知道如何解决。有什么帮助吗?


6
尝试转换成这样的列表。objects.List()。Select(...
内尔森·埃尔多罗

Answers:


114

objectsLinq-To-SQL数据库上下文吗?在这种情况下,只能使用=>运算符右侧的简单表达式。原因是,这些表达式不执行,而是转换为SQL以针对数据库执行。试试这个

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

102

您可以在lamba表达式中将语句主体用于IEnumerable集合。试试这个:

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

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

注意:
使用此方法时仔细考虑,因为这样,您会将所有查询结果存储在内存中,这可能会对其余代码产生不良影响。


4
+1我喜欢这个!加AsEnumerable()口罩我的问题就消失了!
乔尔,

5
这是真正的解决方案,在某些情况下难以应用公认的答案
Ferran Salguero

15
不,这不是真正的答案。这将使您的查询在客户端执行。请参考此问题的详细信息:stackoverflow.com/questions/33375998/...
卢克VO

1
@DatVM这取决于您要执行的操作。这不能总是正确的选择,当然也不能总是错误的选择。
阿米尔·奥维西

3
尽管我同意您的意见,但OP表示他正在使用EntityFramework。在大多数情况下,使用EF时,您希望数据库侧做尽可能多的工作。如果您在回答中注明情况,那将是很好的。
路加·沃

39

这意味着您不能在需要将lambda表达式转换为表达式树的地方(例如,使用linq2sql的情况)将带有“语句主体”的lambda表达式(即使用花括号的lambda表达式)使用。


37
您...稍微改错了。@蒂姆·罗杰斯(Tim Rogers)的回答要好得多
vbullinger 2013年

2
@vbullinger在一定程度上是对的,但是从更一般的意义上讲(在linq-to-sql的上下文之外),这是一个更直接的答案。它帮助我解决了AutoMapper错误
mlhDev 2014年

1
vbullinger:但这确实对我有帮助。
保罗

7

在不了解您在做什么的情况下(Linq2Objects,Linq2Entities,Linq2Sql?),这应该可以使它工作:

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

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

11
这将强制查询对象进行评估。
smartcaveman 2011年

但是,在这种情况下可以,因为无论如何他都会立即调用ToArray()。
smartcaveman 2011年

2
不一定-谁知道“ o”有多大?它可能有50种属性,当我们想要的是2
kdawg

1
使用此技术时,我喜欢在致电之前将要使用的字段选择为匿名类型.AsEnumerable()
Blake Mitchell 2014年

4

使用以下select重载:

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

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

这对我有用,但是当与Entity Framework一起使用时,此解决方案将阻止dbcontext首先将所有行加载到内存中,就像AsEnumerable()那样吗?
议会

2
@parliament:为防止将所有行加载到内存中,应使用Expression<Func<Obj,Obj>>
Mohsen 2014年

4

LINQ to SQL返回对象正在实现IQueryable接口。因此,对于Select方法谓词参数,您应仅提供单个lambda表达式,而不使用主体。

这是因为LINQ for SQL代码不在程序内部执行,而不是在像SQL Server或其他服务器这样的远程端执行。这种惰性加载执行类型是通过实现IQueryable来实现的,该类的预期委托被包装在Expression类型类中,如下所示。

Expression<Func<TParam,TResult>>

表达式树不支持带body的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;

2

这意味着不能将TDelegate包含a 的Lambda类型的表达式([parameters]) => { some code };转换为Expression<TDelegate>。这是规则。

简化查询。您提供的代码可以重写为以下内容并进行编译:

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

1

Arr基本类型Obj吗?是否存在Obj类?仅当Arr是Obj的基本类型时,您的代码才有效。您可以尝试以下方法:

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

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

1

对于您的特定情况,主体是用于创建变量,然后切换到,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#编码约定

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.