C#:是否可以在匿名方法中声明局部变量?

时间:2008-12-15 18:50:11

标签: c# linq-to-sql lambda anonymous-methods

可以在匿名c#方法中使用局部变量,即在以下代码中我只想执行一次计数。

IQueryable<Enquiry> linq = db.Enquiries;

if(...) linq = linq.Where(...);

if(...) linq = linq.Where(e => 
    (x <= (from p in db.Orders where p.EnquiryId == e.Id select p).Count() && 
        (from p in db.Orders where p.EnquiryId == e.Id select p).Count() <= y));

if(...) linq = linq.Where(...);

var result = (from e in linq select e);

匿名函数是否有“让”?

更新: 请注意,我在此语句后添加了几个Where子句,因此无法使用select关闭。

/尼尔斯

6 个答案:

答案 0 :(得分:26)

是的,为什么不呢?!毕竟这是一个功能,只是匿名!

示例:

 x => { int y = x + 1; return x + y; }

或者:

 delegate(int x) {
     int y = x + 1;
     return x + y;
 }

所以你的代码可以写成:

  ... = linq.Where(e => {
         var count = (from p in db.Orders where p.EnquiryId == e.Id select p).Count();
         return x <= count && count <= y;
  });

更新:为了澄清评论的内容,了解匿名方法和lambda表达式之间的区别非常重要。匿名方法就像普通方法一样,没有明确的名称。编译时,编译器会生成一个带有奇怪名称的普通方法,因此它没有任何特殊限制。但是,匿名方法的一种表示形式是lambda表达式。 Lambda表达式可以用几种不同的方式解释。第一个是代表。这样,它们就等于匿名方法。第二个是表达式树。这种方式通常由LINQ to SQL和其他一些LINQ提供程序使用。它们不会以任何方式直接执行您的表达式。它们将其解析为表达式树,并使用树作为输入数据来生成要在服务器上运行的等效SQL语句。它不像方法那样执行,也不被认为是匿名方法。在这种情况下,您无法定义局部变量,因为无法将lambda解析为表达式树。

答案 1 :(得分:7)

是的,您可以完全按照自己的意愿,在Linq中对象和Linq to SQL。

Linq中有一个let,允许您根据需要为查询中间的中间结果命名。根据您的示例:

... = from e in linq 
      let count = (from p in db.Orders where p.EnquiryId == e.Id select p).Count()
      where (x <= count) && (count <= y)
      select e;

顺便说一句,我认为你的原始例子存在语法上的错误,当count只是一个名字时,更容易发现:

where (x <= count) && /* <= */ (count <= y);

答案 2 :(得分:2)

如果你使用Linq to SQL,你将无法使用Mehrdad Afshari的答案。您的LINQ表达式需要是表达式树,而那些不支持匿名委托语法。

你也不能在其他地方创建你的委托并从lambda内部调用它 - Linq to SQL只允许在查询体中执行某些操作,而调用委托不是其中之一。 / p>

你最好的选择,假设你正在使用Linq to SQL(如你的例子所示),是在一个查询中降低计数,然后捕获需要计数的查询中的count变量。

答案 3 :(得分:1)

Where方法接受一个Func所以你在第二部分传递的内容实际上并不是一个方法,而只是一个bool表达式。我的建议是有一个实际的方法返回一个bool,它接收你需要的参数,并且在你调用Where方法时你只需要做这样的事情在哪里(p =&gt; MyMethod(p,...) )

答案 4 :(得分:0)

在Scheme中有一点背景知识你会知道'let'只是定义lambda并调用它的语法糖。

所以有了这些知识,让我们看看它是如何完成的。

(count => x <= count && count <= y)
  ((from p in db.Orders 
    where p.EnquiryId == e.Id 
    select p).Count())

作为奖励,它看起来也像Scheme:)

免责声明:我没有测试这个片段,但没有理由不应该这样做。就个人而言,我只想使用LINQ中提供的'let'结构。

<强>更新

它不起作用...... :(

答案 5 :(得分:0)

我遇到了类似的问题。解决方案是创建自定义表达式树生成方法。

我在MSDN论坛上问了我的问题。请在此处查看问题和答案:Reusing Where expressions

这可能会让你知道如何继续,但我必须承认自定义表达树不适合胆小的人; - )