ChatGPT解决这个技术问题 Extra ChatGPT

“带有语句体的 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();

我不知道错误是什么意思,最重要的是如何解决它。有什么帮助吗?

尝试转换为这样的列表。对象.List().Select(...

T
Tim Rogers

objects 是 Linq-To-SQL 数据库上下文吗?在这种情况下,您只能在 => 右侧使用简单的表达式。操作员。原因是,这些表达式没有被执行,而是被转换为 SQL 以针对数据库执行。尝试这个

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

好的,但是如果我使用单个对象而不是 IEnumerable 怎么办?变得棘手:stackoverflow.com/questions/50837875/…
A
Amir Oveisi

您可以在 IEnumerable 集合的 Lamba 表达式中使用语句体。试试这个:

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

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

注意:使用此方法时请仔细考虑,因为这样一来,您会将所有查询结果都保存在应用程序的内存中,这可能会对您的其余代码产生不必要的副作用。


+1 我喜欢这个!添加 AsEnumerable() 掩盖了我的问题!
这是真正的解决方案,接受的答案在某些情况下很难应用
不,这不是真正的答案。它会使您的查询在客户端执行。有关详细信息,请参阅此问题:stackoverflow.com/questions/33375998/…
@DatVM 这取决于您要做什么。这不可能总是正确的选择,当然也不可能总是错误的选择。
虽然我同意你的观点,但 OP 表示他正在使用 EntityFramework。大多数情况下,在使用 EF 时,您希望数据库端做尽可能多的工作。如果您在答案中注意到这种情况,那就太好了。
s
sepp2k

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


你......稍微改写了错误。 @Tim Rogers 的回答要好得多
@vbullinger 在某种程度上你是对的,但在更一般的意义上(在 linq-to-sql 的上下文之外),这是一个更直接的答案。它帮助我解决了 AutoMapper 错误
vbullinger:不过,它确实帮助了我。
vbullinger:我得到了这个错误,而不是 Linq-To-SQL 问题。
请提供答案!
s
spender

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

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

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

这迫使可查询对象进行评估。
但是,在这种情况下没关系,因为无论如何他都会调用 ToArray() 。
不一定——谁知道“o”有多大?当我们只需要 2 个时,它可能有 50 个属性。
使用此技术时,我喜欢在调用 .AsEnumerable() 之前将我将使用的字段选择为匿名类型
A
Azri Jamil

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

这是因为 LINQ for SQL 代码不是在程序内部执行,而是在远程端(如 SQL 服务器或其他)执行。这种延迟加载执行类型是通过实现 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;

M
Mohsen

使用这个重载的选择:

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

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

这对我有用,但是当与实体框架一起使用时,这个解决方案会阻止 dbcontext 首先将所有行加载到内存中,就像 AsEnumerable() 一样?
@parliament:为防止将所有行加载到内存中,您应该使用 Expression<Func<Obj,Obj>>
M
Matthias Burger

参加聚会已经晚了 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()


我刚看了这个!当我看到一篇 9 年前的帖子有“一个新的答案已添加到这个帖子”时,希望你能看到我脸上的阴谋。哈哈哈好时机。
@TeaBaerd 哈哈是的。 :D 巧合有时很有趣...
如何在 linq 中包含嵌套表?我必须使用加入/
@Ali.Rashidi 与 from o in objects.Include(x=>x.Nested) let ... 应该可以工作。
H
Harsh Baid

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

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

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

A
Atanas Korchev

ArrObj 的基本类型吗? Obj 类是否存在?仅当 Arr 是 Obj 的基本类型时,您的代码才有效。你可以试试这个:

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

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

L
Luke Vo

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


T
Tovar

如其他回复所述,您只能在 => 运算符右侧使用简单表达式。我建议这个解决方案,它只包括创建一个方法来执行您想要在 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 };
}

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅