带有语句体的lambda表达式不能转换为表达式树;

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

我不知道这个错误意味着什么,最重要的是如何修复它。任何帮助吗?

150982 次浏览

ArrObj的基类型吗?Obj类存在吗?你的代码只有在Arr是Obj的基类型时才能工作。你可以试试这个:

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


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

不知道更多关于你在做什么(Linq2Objects, Linq2Entities, Linq2Sql?),这应该使它工作:

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


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

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

objects是一个Linq-To-SQL数据库上下文吗?在这种情况下,只能使用=>运算符右侧的简单表达式。原因是,这些表达式不会被执行,而是被转换为SQL,然后对数据库执行。 试试这个< / p >
Arr[] myArray = objects.Select(o => new Obj() {
Var1 = o.someVar,
Var2 = o.var2
}).ToArray();

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

简化您的查询。你提供的可以重写如下,并将编译:

Arr[] myArray = objects.Select(o => new Obj()
{
Var1 = o.someVar,
Var2 = o.var2
} ).ToArray();
你可以在IEnumerable集合的lamba表达式中使用语句体。 试试这个:

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


return new Obj()
{
Var1 = someLocalVar,
Var2 = o.var2
};
}).ToArray();
< p > 注意:
在使用这种方法时要仔细考虑,因为这样一来,所有的查询结果都将保存在应用程序的内存中,这可能会对其余的代码产生不必要的副作用

使用重载select:

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


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

对于您的特定情况,body是用于创建变量,切换到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#编码惯例

LINQ to SQL返回对象正在实现IQueryable接口。因此,对于Select方法谓词参数,您应该只提供单个没有正文的lambda表达式。

这是因为SQL代码的LINQ不是在程序内部执行,而不是像SQL server或其他服务器那样在远程端执行。这种延迟加载执行类型是通过实现IQueryable来实现的,其中它的期望委托被包装在表达式类型类中,如下所示。

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;

9年的时间太晚了,但是用不同的方法来解决你的问题(没有人提到过吗?)

语句体在Func<>中工作得很好,但在Expression<Func<>>中行不通。IQueryable.Select需要一个Expression<>,因为它们可以转换为实体框架——Func<>不能。

所以你要么使用AsEnumerable并开始处理内存中的数据(不建议,如果不是真的必要),要么继续使用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()

正如在其他回复中所述,只能使用=>操作符右侧的简单表达式。我建议这个解决方案,它只包括创建一个方法,做你想要在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 };
}