使用LINQ遇到的问题,请高手解答下原理
潜意识中知道这是IEnumerable的延迟特性造成的,但是硬要条条框框地从原理上解释还真发现自己不行,所以来问问高手们了,同时我想也可以作为一个较为典型的问题,供使用着LINQ的开发者注意一下
直接看题目吧:
首先有一个MyClass类,代码如下
接着在Main函数中用两种方式返回一个MyClass的集合,分别是GetEnumerable和GetList
然后调用如下
对于第二种情况,输出的是预期的2, 3, 4
而对于第一种情况,很遗憾,输出的是1, 2, 3
根据单步调试的结果, 事实上返回AsEnumerable()时,那个Select(i => new MyClass(i))每次foreach都要执行
还请高手说下原理,谢谢~
直接看题目吧:
首先有一个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);
}
}
{
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 };{
return
intArray
.Select(i => new MyClass(i))
.AsEnumerable();
}
private static IEnumerable<MyClass> GetList()
{
return
intArray
.Select(i => new MyClass(i))
.ToList();
}
然后调用如下
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{
//第一种情况,使用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();
}
对于第二种情况,输出的是预期的2, 3, 4
而对于第一种情况,很遗憾,输出的是1, 2, 3
根据单步调试的结果, 事实上返回AsEnumerable()时,那个Select(i => new MyClass(i))每次foreach都要执行
还请高手说下原理,谢谢~