LINQ的Func <bool>只被调用一次?</bool>

时间:2015-01-27 15:34:32

标签: c# linq

我迷失了google的关键字...有谁可以请我指向MSDN页面或SO解答解释为什么Foo()只被调用一次?特别是因为First只有一个带谓词的重载。这里有什么优化?

using System;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var foo = "Foo".First(Foo().Contains); // x 1
            var bar = "Bar".First(c => Bar().Contains(c)); // x 3
            var baz = "Baz".First(c => { return Baz().Contains(c); }); // x 3

            Console.ReadLine();
        }

        private static string Foo()
        {
            Console.WriteLine("Foo");
            return "__o";
        }

        private static string Bar()
        {
            Console.WriteLine("Bar");
            return "__r";
        }

        private static string Baz()
        {
            Console.WriteLine("Baz");
            return "__z";
        }
    }
}

编辑:

除了接受和赞成的答案(谢谢)之外,通过ILSpy运行它也有助于在视觉上澄清我的订单。

private static void Main(string[] args)
{
    char foo = "Foo".First(new Func<char, bool>(Program.Foo().Contains<char>));
    char bar = "Bar".First((char c) => Program.Bar().Contains(c));
    char baz = "Baz".First((char c) => Program.Baz().Contains(c));
    Console.ReadLine();
}

3 个答案:

答案 0 :(得分:25)

Foo()只会调用一次,因为您传递给First()的表达式为Foo().Contains

要评估此表达式,只需调用Foo()一次。

让我们考虑第一个和第二个片段之间的差异:

"Foo".First(Foo().Contains);

此处,First()需要Func<char, bool>个参数。调用Foo()(一次),并对结果执行Contains的成员访问。该成员访问的结果确实是Func<char, bool>,因此代码有效,并且该委托被传递给First()"Foo"继续为Foo()中的每个字符调用它。请注意,我们已在此处调用Foo(),因为调用代理并不意味着我们必须再次评估"Bar".First(c => Bar().Contains(c));

Func<char, bool>

此处,传递给First()的{​​{1}}是lambda表达式c => Bar().Contains(c)First()将继续为"Bar"中的每个角色调用该委托。 &#34;身体&#34;每次调用都会执行lambda表达式,这会导致Bar()被调用三次。

答案 1 :(得分:16)

您需要将其拆分为直接查看原因:

var foo = "Foo".First(Foo().Contains);

基本上是:

string foo = Foo();                    // only called once
Func<char, bool> func = foo.Contains;  // = "__o".Contains
var foo = "Foo".First(func);

如您所见,Foo仅被调用一次并返回“__o”。然后Func<char, bool>所需的First委托取自该字符串,这基本上意味着它是字符串“__o”上的Contains而不是方法Foo,因此“Foo” “只打印一次。

在另外两种情况下,你传入一个Lambda表达式,然后为每个字符调用 - 以与上面相同的方式进行分割:

Func<char, bool> func = c => Bar().Contains(c);
var bar = "Bar".First(func);

这里没有调用Bar来构造Func<char, bool>,因为它只在其内部被称为“内部”,这就是为什么Bar在每次调用Func<char, bool>时被调用{{1}} 1}}。

答案 2 :(得分:4)

在所有三种情况下,您传递的函数都接受一个字符并返回一个布尔值。并且在所有情况下,将对字符串中的每个字符执行该函数。不同之处在于如何定义这些功能。

var foo = "Foo".First(Foo().Contains); // x 1

在这里,您将该函数定义为属于Contains返回的对象的Foo()函数。要使Foo()只需要执行一次。

var bar = "Bar".First(c => Bar().Contains(c)); // x 3
var baz = "Baz".First(c => { return Baz().Contains(c); }); // x 3

在这两种情况下,您定义的函数最终会在函数调用中调用Bar()Baz()