潜意识中知道这是IEnumerable的延迟特性造成的,但是硬要条条框框地从原理上解释还真发现自己不行,所以来问问高手们了,同时我想也可以作为一个较为典型的问题,供使用着LINQ的开发者注意一下
直接看题目吧:
首先有一个MyClass类,代码如下
public
class
MyClass

{
private int i = 0;

public MyClass(int i)

{
this.i = i;
}

public void MethodA()

{
i++;
}

public void MethodB()

{
Console.WriteLine(i);
}
}
接着在Main函数中用两种方式返回一个MyClass的集合,分别是GetEnumerable和GetList
private
static
IEnumerable
<
MyClass
>
GetEnumerable()

{
return
intArray
.Select(i => new MyClass(i))
.AsEnumerable();
}

private
static
IEnumerable
<
MyClass
>
GetList()

{
return
intArray
.Select(i => new MyClass(i))
.ToList();
}
两个方法唯一的区别就在于,一个用了AsEnumerable,一个用了ToList,这里的intArray是早选定义好的private statice int[] intArray = new int[] { 1, 2, 3 };
然后调用如下
public
static
void
Main(
string
[] args)

{
//第一种情况,使用Enumerable
IEnumerable<MyClass> ms = GetEnumerable();
Console.WriteLine("第一种情况:");
foreach (MyClass m in ms)

{
m.MethodA();
}
foreach (MyClass m in ms)

{
m.MethodB();
}

//第二种情况,虽然ms还是IEnumberable,但事实上对象是个List
ms = GetList();
Console.WriteLine("第二种情况:");
foreach (MyClass m in ms)

{
m.MethodA();
}
foreach (MyClass m in ms)

{
m.MethodB();
}

Console.Read();
}
对于每一种情况,都先执行MethodA使内部的i加上1,然后执行MethodB输出i
对于第二种情况,输出的是预期的2, 3, 4
而对于第一种情况,很遗憾,输出的是1, 2, 3
根据单步调试的结果, 事实上返回AsEnumerable()时,那个Select(i => new MyClass(i))每次foreach都要执行
还请高手说下原理,谢谢~