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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/369334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 00:47:51  来源:igfitidea点击:

C#: Is it possible to declare a local variable in an anonymous method?

c#linq-to-sqllambdaanonymous-methods

提问by Niels Bosma

Is is possible to have a local variable in an anonymous c# methods, i.e. in the following code I would like to perform the count only once.

是否可以在匿名 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);

Is there a "let" for anonymous functions?

匿名函数有“让”吗?

Update: Note that I'm adding several Where clauses after this statement so I can't close with a select.

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

/Niels

/尼尔斯

采纳答案by Torben Rahbek Koch

I've run into a similar problem. The solution is to create a custom expression tree generating method.

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

I asked my question on MSDN-forums. Please see the question and answer here: Reusing Where expressions.

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

This may give you an idea on how to proceed, but I must admit that custom expression trees are not for the faint-hearted ;-)

这可能会让你对如何进行有一个想法,但我必须承认自定义表达式树不适合胆小的人;-)

回答by Mehrdad Afshari

Yes, why not?! After all it's a function, just anonymous!

是的,为什么不?!毕竟它是一个函数,只是匿名的!

Example:

例子:

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

Or alternatively:

或者:

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

So your code can be written as:

所以你的代码可以写成:

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

UPDATE: To clarify things about the comment, it's important to know the difference between anonymous methods and lambda expressions. An anonymous method is just like a normal method, without an explicit name. When you compile it, the compiler generates a normal method with a weird name for you instead, so it will not have any special limitations. However, one representation of an anonymous method is a lambda expression. Lambda expressions can be interpreted in a couple different ways. The first is a delegate. In that way, they are equal to an anonymous method. The second is an expression tree. This way is normally used by LINQ to SQL and some other LINQ providers. They don't execute your expression directly by any means. They parse it as an expression tree and use the tree as input data to generate the equivalent SQL statement to be run on the server. It's not executed like a method and it's not considered an anonymous method. In that case, you can't define a local variable as it's not possible to parse the lambda as an expression tree.

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

回答by BFree

The Where method takes a Func so what you're passing in there in the second part ins't actually a method, but just a bool expression. My suggestion would be to have an actual method that returns a bool, that takes in the paremeters you need, and in your call to the Where method you just do something like this Where(p=> MyMethod(p,...))

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

回答by Erik Forbes

If you're using Linq to SQL, you won't be able to use Mehrdad Afshari's answer. Your LINQ expressions need to be Expression Trees, and those don't support the anonymous delegate syntax.

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

Neither will you be able to create your delegate elsewhere and call it from inside the lambda - Linq to SQL only allows certain operations to be performed in the body of the query, and calling a delegate isn't one of them.

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

Your best bet, assuming you're using Linq to SQL (as it appears given your example), is to bring down the count in one query, then capture the count variable in the query that requires the count.

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

回答by Daniel Earwicker

Yes, you can do exactly what you want, in Linq to objects and Linq to SQL.

是的,您可以在 Linq to objects 和 Linq to SQL 中做您想做的事情。

There is a letin Linq, allowing you to give a name to an intermediate result in the middle of your query, just as you want to. Based on your example:

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

... = 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;

By the way, I think there was something syntactically erroneous about your original example, which is easier to spot when the countis just a name:

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

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

回答by leppie

With a little background in Scheme you would know that 'let' is just syntax sugar for defining a lambda and invoking it.

稍加了解 Scheme 背景,您就会知道“let”只是用于定义 lambda 并调用它的语法糖。

So with that knowledge, lets see how it can be done.

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

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

As a bonus, it looks like Scheme too :)

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

Disclaimer: I did not test this snippet, but there is no reason it should not work. Personally, I would just use the 'let' construct provided in LINQ.

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

Update:

更新:

It does not work... :(

这是行不通的... :(