我正在使用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 集合的 lba 表达式中使用语句主体。 试试这个:
Obj[] myArray = objects.AsEnumerable().Select(o =>
{
var someLocalVar = o.someVar;
return new Obj()
{
Var1 = someLocalVar,
Var2 = o.var2
};
}).ToArray();
注意事项:
使用此方法时请仔细考虑,因为这样,您将在应用程序的内存中获得所有查询结果,这可能会对代码的其余部分产生不必要的副作用。
这意味着您不能在需要将 lambda 表达式转换为表达式树的地方(例如使用 linq2sql 时的情况)使用带有“语句主体”的 lambda 表达式(即使用大括号的 lambda 表达式) ).
如果不了解更多关于您正在做什么的信息(Linq2Objects、Linq2Entities、Linq2Sql?),这应该可以使其工作:
Arr[] myArray = objects.AsEnumerable().Select(o => {
var someLocalVar = o.someVar;
return new Obj() {
Var1 = someLocalVar,
Var2 = o.var2
};
}).ToArray();
LINQ to SQL 返回对象正在实现
IQueryable
接口。因此,对于 Select
方法谓词参数,您应该只提供没有主体的单个 lambda 表达式。
这是因为 LINQ for SQL 代码不是在程序内部执行,而是在远程端(如 SQL Server 或其他服务器)执行。这种延迟加载执行类型是通过实现 IQueryable 来实现的,其中它的期望委托被包装在如下所示的表达式类型类中。
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;
晚了 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()
使用 select 的重载:
Obj[] myArray = objects.Select(new Func<Obj,Obj>( o =>
{
var someLocalVar = o.someVar;
return new Obj()
{
Var1 = someLocalVar,
Var2 = o.var2
};
})).ToArray();
这意味着包含
TDelegate
的 ([parameters]) => { some code };
类型的 Lambda 表达式无法转换为 Expression<TDelegate>
。 这是规矩。
简化您的查询。 您提供的可以重写如下并编译:
Arr[] myArray = objects.Select(o => new Obj()
{
Var1 = o.someVar,
Var2 = o.var2
} ).ToArray();
Arr
是Obj
的基本类型吗? Obj 类存在吗?仅当 Arr 是 Obj 的基本类型时,您的代码才有效。你可以试试这个:
Obj[] myArray = objects.Select(o =>
{
var someLocalVar = o.someVar;
return new Obj()
{
Var1 = someLocalVar,
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# 编码约定
正如其他回复中所述,您只能使用
=>
运算符右侧的简单表达式。我建议这个解决方案,它只需要创建一个方法来执行您想要在 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 };
}
如果您来到这里是因为这是此错误的最佳谷歌结果,但您没有使用列表,那么您总是可以像这样快速而肮脏地做一些事情:
我的原始代码:
RuleFor(m => m.DocumentName).Must( ...etc...
我想深入研究
m
并且我知道 m
是 FileUploadDTO
类型,并且在上面的表达式中它试图返回一个字符串,所以我添加了以下可以设置断点的方法:
private string GetIt(FileUploadDTO dto)
{
return dto.FileName;
}
然后:
RuleFor(m => GetIt(m)).Must( ...etc...