【问题标题】:"A lambda expression with a statement body cannot be converted to an expression tree"“带有语句体的 lambda 表达式不能转换为表达式树”
【发布时间】:2011-07-07 22:50:47
【问题描述】:

在使用 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.List().Select(...

标签: c# linq entity-framework linq-to-entities


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    您可以在 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 时,您希望数据库端做尽可能多的工作。如果您在回答中注明该案例,那就太好了。
    【解决方案3】:

    这意味着您不能在需要将 lambda 表达式转换为表达式树的地方(例如,当使用 linq2sql)。

    【讨论】:

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

    如果不知道更多关于你在做什么(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()之前将我将使用的字段选择为匿名类型
    【解决方案5】:

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

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

    Expression<Func<TParam,TResult>>
    

    表达式树不支持带正文的 lambda 表达式,它只支持像 var id = cols.Select( col =&gt; col.id ); 这样的单行 lambda 表达式

    因此,如果您尝试以下代码将无法正常工作。

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

    以下将按预期工作。

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

    【讨论】:

      【解决方案6】:

      使用这个重载的选择:

      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&lt;Func&lt;Obj,Obj&gt;&gt;
      【解决方案7】:

      晚了 9 年,但对你的问题采取了不同的方法(没人提到?):

      语句主体与Func&lt;&gt; 一起工作正常,但不适用于Expression&lt;Func&lt;&gt;&gt;IQueryable.Select 想要一个 Expression&lt;&gt;,因为它们可以翻译为实体框架 - Func&lt;&gt; 不能。

      因此,您要么使用AsEnumerable 并开始处理内存中的数据(不推荐,如果不是真的必要),或者您继续使用推荐的IQueryable&lt;&gt;。 有一个叫做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 中包含嵌套表?我必须使用 join /
      • @Ali.Rashidi 和 from o in objects.Include(x=&gt;x.Nested) let ... 应该可以工作。
      【解决方案8】:

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

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

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

      【讨论】:

        【解决方案9】:

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

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

        【讨论】:

          【解决方案10】:

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

          【讨论】:

            【解决方案11】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-08-08
              • 2016-06-01
              • 2012-01-15
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多