一、结论
使用yield return得到的集合相较于直接使用list,在于yield return支持延迟加载,也就是说,对于一个有一百万数据量的集合,只使用了前五项。如果使用yield return,在内存中只会加载前五项的数据,但是使用list就会将一百万的数据一次性全部加载到内存中。懒加载在大多数情况下都是有利的。
二、实验过程
public class Dashboard
{
public float[] temps = new float[10]
{
56.2F,56.7F,56.9F,58.8F,61.3F,65.9F,62.1F,59.2F,57.5F,56.5F
};
public List<float> GetFloatList()
{
List<float> list = new List<float>();
foreach (var item in temps)
{
if (item > 57)
{
Console.WriteLine("执行一次list");
list.Add(item);
}
}
return list;
}
public IEnumerable<float> GetFloatEnum()
{
foreach (var item in temps)
{
if (item > 57)
{
Console.WriteLine("执行一次yield return");
yield return item;
}
}
}
}
Dashboard dashboard = new Dashboard();
var result2 = dashboard.GetFloatEnum();
Console.WriteLine(result2.First());
Console.WriteLine("please press enter...");
Console.ReadKey();
var result3 = dashboard.GetFloatList();
Console.WriteLine(result3.First());
Console.ReadLine();
/*
* //延迟加载
执行一次yield return
58.8
please press enter...
执行一次list
执行一次list
执行一次list
执行一次list
执行一次list
执行一次list
58.8
*/
由此可见,再只取用集合的第一项的时候,yield return只执行了一次,而list却执行了很多次。
Dashboard dashboard = new Dashboard();
var result2 = dashboard.GetFloatEnum();
Console.WriteLine(result2.ToList()[0]);
Console.WriteLine("please press enter...");
Console.ReadKey();
var result3 = dashboard.GetFloatList();
Console.WriteLine(result3[0]);
Console.ReadLine();
//一旦调用tolist就失去延迟加载的效果,在调用tolist的过程中将所有集合执行完
执行一次yield return
执行一次yield return
执行一次yield return
执行一次yield return
执行一次yield return
执行一次yield return
58.8
please press enter...
执行一次list
执行一次list
执行一次list
执行一次list
执行一次list
执行一次list
58.8
结论:在IEnumerable上调用ToList()会致使代码执行所有迭代,效果等同于直接使用List。
三、使用技巧实例
下面示例一个较复杂的自定义集合的使用,一般使用形式如下:
private IEnumerable<TankReading> ConvertToTankReadings(DataTable dataTable)
{
var tankReadings = new List<TankReading>();
foreach (DataRow row in dataTable.Rows)
{
var tankReading = new TankReading
{
TankReadingsID = Convert.ToInt32(row["TRReadingsID"]),
TankID = Convert.ToInt32(row["TankID"]),
ReadingDateTime = Convert.ToDateTime(row["ReadingDateTime"]),
ReadingFeet = Convert.ToInt32(row["ReadingFeet"]),
ReadingInches = Convert.ToInt32(row["ReadingInches"]),
MaterialNumber = row["MaterialNumber"].ToString(),
EnteredBy = row["EnteredBy"].ToString(),
ReadingPounds = Convert.ToDecimal(row["ReadingPounds"]),
MaterialID = Convert.ToInt32(row["MaterialID"]),
Submitted = Convert.ToBoolean(row["Submitted"]),
};
tankReadings.Add(tankReading);
}
return tankReadings.AsEnumerable();
}
采用yield实现懒加载如下,建议采用懒加载的方法
private IEnumerable<TankReading> ConvertToTankReadings(DataTable dataTable)
{
foreach (DataRow row in dataTable.Rows)
{
yield return new TankReading
{
TankReadingsID = Convert.ToInt32(row["TRReadingsID"]),
TankID = Convert.ToInt32(row["TankID"]),
ReadingDateTime = Convert.ToDateTime(row["ReadingDateTime"]),
ReadingFeet = Convert.ToInt32(row["ReadingFeet"]),
ReadingInches = Convert.ToInt32(row["ReadingInches"]),
MaterialNumber = row["MaterialNumber"].ToString(),
EnteredBy = row["EnteredBy"].ToString(),
ReadingPounds = Convert.ToDecimal(row["ReadingPounds"]),
MaterialID = Convert.ToInt32(row["MaterialID"]),
Submitted = Convert.ToBoolean(row["Submitted"]),
};
}
}