yield,它可以讓程式員以傳回每個元素的方式來自動產生IEnumerable<T>物件
例如下列程式會回傳1-5 五個數字的IEnumerable<T>物件:
這是一般的寫法,因為List<T>有實作IEnumerable<T>,所以很自然的會用List<T>作為產製IEnumerable<T>的寫法。
static IEnumerable<int> GetCollection1()
{
List<int> list = new List<int>();
for (int i = 1; i <= 5; i++)
{
list.Add(i);
}
return list;
}
改為yield寫法,看起來更為精簡,yield指令會告訴編譯器,這一段函式的回傳值IEnumerable<T>內的元素由yield return所回傳的物件來填充,因此可省下額外使用集合物件事先封裝的工作。
static IEnumerable<int> GetCollection2()
{
for (int i = 1; i <= 5; i++)
{
yield return i;
}
}
比較二個方式的效能
private static int testMax = 5000000;
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
var result = GetCollection1();
sw.Stop();
Console.WriteLine("Collection1:{0},count:{1}", sw.ElapsedMilliseconds, result.Count());
sw.Restart();
var result2 = GetCollection2();
sw.Stop();
Console.WriteLine("Collection2:{0},count:{1}", sw.ElapsedMilliseconds, result2.Count());
sw.Restart();
var result4 = GetCollection4();
sw.Stop();
Console.WriteLine("Collection4:{0},count:{1}", sw.ElapsedMilliseconds, result4.Count());
sw.Restart();
var result5 = GetCollection5();
sw.Stop();
Console.WriteLine("Collection5:{0},count:{1}", sw.ElapsedMilliseconds, result5.Count());
}
static IEnumerable<int> GetCollection1()
{
List<int> list = new List<int>();
for (int i = 1; i <= testMax; i++)
{
list.Add(i);
}
return list;
}
static IEnumerable<int> GetCollection2()
{
for (int i = 1; i <= testMax; i++)
{
yield return i;
}
}
static IEnumerable<Student> GetCollection4()
{
for (int i = 1; i <= testMax; i++)
{
yield return new Student()
{
Id = i,
Name = i.ToString()
};
}
}
static IEnumerable<Student> GetCollection5()
{
List<Student> studentList = new List<Student>();
for (int i = 1; i <= testMax; i++)
{
studentList.Add(new Student() {Id=i,Name=i.ToString() });
}
return studentList;
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
執行結果,我們發現使用yield寫法,所執行時間為0,這是因為延遲查詢,當我們對這個集合查詢時才會真正載入資料。
//查詢階段才會真正載入資料
Console.WriteLine(result4.Where(o => o.Id == 700).Select(o => o.Name).FirstOrDefault());
若是在foreach這類迭代運算中要中斷執行,則可利用yield break來中斷,如下程式碼:
static IEnumerable<int> GetCollection3(IEnumerable<int> NumberSeries)
{
foreach (var number in NumberSeries)
{
if (number > 10)
{
yield break;
}
else
{
yield return number;
}
}
}
執行結果
Read more...