13

是否可以在匿名 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 子句,因此我无法通过选择关闭。

/尼尔斯

4

6 回答 6

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 解析为表达式树。

于 2008-12-15T18:51:59.077 回答
7

是的,你可以在 Linq to objects 和 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;

顺便说一句,我认为您的原始示例在语法上存在一些错误,当 thecount只是一个名称时更容易发现:

where (x <= count) && /* <= */ (count <= y);
于 2008-12-15T19:10:28.523 回答
2

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

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

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

于 2008-12-15T19:01:40.117 回答
1

Where 方法采用 Func,因此您在第二部分中传递的内容实际上并不是一个方法,而只是一个布尔表达式。我的建议是有一个返回布尔值的实际方法,它接受你需要的参数,在你调用 Where 方法时,你只需执行类似 Where(p=> MyMethod(p,...)) 的操作

于 2008-12-15T18:57:31.500 回答
0

稍微了解一下 Scheme 的背景知识,您就会知道 'let' 只是用于定义 lambda 并调用它的语法糖。

因此,有了这些知识,让我们看看如何做到这一点。

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

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

免责声明:我没有测试这个片段,但没有理由它不应该工作。就个人而言,我只会使用 LINQ 中提供的“让”构造。

更新:

这没用... :(

于 2008-12-16T08:32:23.443 回答
0

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

我在 MSDN 论坛上问了我的问题。请在此处查看问题和答案:重用 Where 表达式

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

于 2008-12-23T23:26:00.043 回答