我迷失了谷歌的关键词...有谁可以请我指向一个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";
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
除了接受和赞成的答案(谢谢),通过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();
}
Run Code Online (Sandbox Code Playgroud)
Fré*_*idi 25
Foo()
只调用一次因为你传递给的表达式First()
是Foo().Contains
.
要评估此表达式,Foo()
只需调用一次.
让我们考虑第一个和第二个片段之间的差异:
"Foo".First(Foo().Contains);
Run Code Online (Sandbox Code Playgroud)
在这里,First()
需要一个Func<char, bool>
说法.Foo()
被调用(一次)并对Contains
结果执行成员访问.该成员访问的结果确实是一个Func<char, bool>
,因此代码是有效的,并且该委托被传递给First()
,该代理继续为其中的每个字符调用它"Foo"
.请注意,我们已完成Foo()
此处的调用,因为调用委托并不意味着我们必须Foo()
再次进行评估.
"Bar".First(c => Bar().Contains(c));
Run Code Online (Sandbox Code Playgroud)
这里,Func<char, bool>
传递给的First()
是lambda表达式c => Bar().Contains(c)
.First()
将继续为每个角色调用该代表"Bar"
.lambda表达式的"主体"在每次调用时执行,这导致Bar()
被调用三次.
Chr*_*Fin 16
你需要拆分它直接看到原因:
var foo = "Foo".First(Foo().Contains);
Run Code Online (Sandbox Code Playgroud)
基本上是:
string foo = Foo(); // only called once
Func<char, bool> func = foo.Contains; // = "__o".Contains
var foo = "Foo".First(func);
Run Code Online (Sandbox Code Playgroud)
如您所见,Foo
仅调用一次并返回"__o".然后Func<char, bool>
需要的委托First
取自该字符串,这基本上意味着它是Contains
字符串"__o"而不是方法Foo
,因此"Foo"只打印一次.
在另外两种情况下,你传入一个Lambda表达式,然后为每个字符调用它 - 以与上面相同的方式分割,这将是:
Func<char, bool> func = c => Bar().Contains(c);
var bar = "Bar".First(func);
Run Code Online (Sandbox Code Playgroud)
这里Bar
没有被称为构造它Func<char, bool>
,因为它只被称为"内部"它的身体,这就是为什么Bar
然后在每次调用时调用它Func<char, bool>
.