有几个不同的东西在这里变得困惑。
后期绑定:这是它被编译之后确定的代码的含义。例如,如果编译器检查x
类型的对象是否具有DoStuff()
方法(考虑扩展方法和默认参数),然后在其输出的代码中产生调用,或者使用编译器失败,则0123ree是早期绑定的否则错误。如果搜索DoStuff()
方法在运行时完成,并且在没有DoStuff()
方法的情况下抛出运行时异常,则这是迟到的。每个人都有优点和缺点,而且C#通常是早期的,但是支持后期绑定(最简单的通过dynamic
,但涉及反思的更复杂的方法也计算在内)。
延迟执行严格地说,所有Linq方法都会立即生成结果。但是,该结果是一个对象,该对象存储对可枚举对象的引用(通常是以前的Linq方法的结果),它将在枚举对象本身枚举时以适当的方式进行处理。例如,我们可以写我们自己的Take
方法:
private static IEnumerable<T> TakeHelper<T>(IEnumerable<T> source, int number)
{
foreach(T item in source)
{
yield return item;
if(--number == 0)
yield break;
}
}
public static IEnumerable<T> Take<T>(this IEnumerable<T> source, int number)
{
if(source == null)
throw new ArgumentNullException();
if(number < 0)
throw new ArgumentOutOfRangeException();
if(number == 0)
return Enumerable.Empty<T>();
return TakeHelper(source, number);
}
现在,当我们使用它:
var taken4 = someEnumerable.Take(4);//taken4 has a value, so we've already done
//something. If it was going to throw
//an argument exception it would have done so
//by now.
var firstTaken = taken4.First();//only now does the object in taken4
//do the further processing that iterates
//through someEnumerable.
捕获的变量:通常情况下,当我们使用一个变量,我们利用如何其当前状态:
int i = 2;
string s = "abc";
Console.WriteLine(i);
Console.WriteLine(s);
i = 3;
s = "xyz";
这是很直观的,这种打印2
和abc
而不是3
和xyz
。在匿名函数和lambda表达式不过,当我们利用我们“捕获”它作为一个可变的变量,所以我们最终会使用它时,委托调用值:
int i = 2;
string s = "abc";
Action λ =() =>
{
Console.WriteLine(i);
Console.WriteLine(s);
};
i = 3;
s = "xyz";
λ();
创建λ
不使用i
和s
的值,但创建了一组关于在调用λ
时如何处理i
和s
的指令。只有在发生这种情况时,才会使用i
和s
的值。
把它放在一起:在你的情况你没有任何后期绑定。这与你的问题无关。
在这两个你都延迟执行。对Take
的呼叫和对Where
的呼叫均返回枚举对象,枚举对象将在枚举对象时对arr
起作用。
只有一个你有捕获的变量。对Take
的呼叫将直接传递给Take
,Take
则使用该值。对Where
的调用传递从lambda表达式创建的Func<int, bool>
,并且该lambda表达式捕获int
变量。 Where
对此捕获一无所知,但Func
确实如此。
这就是他们在对待cutoff
时表现如此不同的原因。
它与后期绑定无关... –