我迷失了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();
}
答案 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()
。