通常使用方法
yield 關鍵字向編譯器指示它所在的方法是迭代器塊
在迭代器塊中,yield 關鍵字與 return 關鍵字結合使用,向枚舉器對象提供值。 這是一個返回值,例如,在
foreach 語句的每一次循環中返回的值。 yield 關鍵字也可與 break 結合使用,表示迭代結束。
不容許不安全塊。
方法、運算符或訪問器的參數不能是 ref 或 out。
yield return 語句不能放在 try-catch 塊中的任何位置。 該語句可放在後跟 finally 塊的 try 塊中。
yield break 語句可放在 try 塊或 catch 塊中,但不能放在 finally 塊中。
yield 語句不能出如今匿名方法中
Yield的執行方法
調用函數
調用者請求item
下一個item返回
回到步驟2
yield不能單獨放在try-catch塊中,若是try中有yield那麼,這個try塊後面不準跟着finally塊;也不能出如今匿名
方法中,因此,看起來yield彷佛並不經常使用,可是也不是不用。我前面有一個關於迭代器的例子《C#中的迭代器基礎
》中就用到了。能夠參考一下那個例子,可是這裏要再說的一點是我後來看到的,yield是跟return一塊兒使用的,形
式爲yield return xxx,通常來講單獨的return在每一個方法中只能存在一個。而yield則不一樣的是,能夠出現連續多
個。
迭代器,是一個連續的集合,出現多個yield return其實就是將這多個的yield return元素按照出現的順序存儲在迭
代器的集合中而已
static IEnumerable<Int32> CountWithTimeLimit(DateTime limit)
{
try
{
for (int i = 1; i <= 100; i++)
{
if (DateTime.Now >= limit)
{
yield break;
}
yield return i;
}
}
finally
{
Console.WriteLine("中止迭代!"); Console.ReadKey();
}
}
static void Main(string[] args)
{
DateTime stop = DateTime.Now.AddSeconds(2);
foreach (Int32 i in CountWithTimeLimit(stop))
{
Console.WriteLine("返回 {0}", i);
Thread.Sleep(300);
}
}
簡單幾行代碼就可以徹底實現IterationSampleIterator類所須要的功能。方法看起來很普通,除了使用了yield
return。這條語句告訴編譯器這不是一個普通的方法,而是一個須要執行的迭代塊(yield block),他返回一個
IEnumerator對象,你可以使用迭代塊來執行迭代方法並返回一個IEnumerable須要實現的類型,IEnumerator或者對
應的泛型。若是實現的是非泛型版本的接口,迭代塊返的yield type是Object類型,不然返回的是相應的泛型類型。
例如,若是方法實現IEnumerable<String>接口,那麼yield返回的類型就是String類型。 在迭代塊中除了yield
return外,不容許出現普通的return語句。塊中的全部yield return 語句必須返回和塊的最後返回類型兼容的類型
。舉個例子,若是方法定義須要返回IEnumeratble<String>類型的話,不能yield return 1 。 須要強調的一點是,
對於迭代塊,雖然咱們寫的方法看起來像是在順序執行,實際上咱們是讓編譯器來爲咱們建立了一個狀態機。這就是
在C#1中咱們書寫的那部分代碼---調用者每次調用只須要返回一個值,所以咱們須要記住最後一次返回值時,在集合
中位置。 當編譯器遇到迭代塊是,它建立了一個實現了狀態機的內部類。這個類記住了咱們迭代器的準確當前位置
以及本地變量,包括參數。這個類有點相似與咱們以前手寫的那段代碼,他將全部須要記錄的狀態保存爲實例變量。
下面來看看,爲了實現一個迭代器,這個狀態機須要按順序執行的操做:
它須要一些初始的狀態
當MoveNext被調用時,他須要執行GetEnumerator方法中的代碼來準備下一個待返回的數據。
當調用Current屬性是,須要返回yielded的值。
須要知道何時迭代結束是,MoveNext會返回false
class Program
{
static readonly String Padding = new String(' ', 30);
static IEnumerable<Int32> CreateEnumerable()
{
Console.WriteLine("{0} CreateEnumerable()方法開始", Padding);
for (int i = 0; i < 3; i++)
{
Console.WriteLine("{0}開始 yield {1}", i);
yield return i;
Console.WriteLine("{0}yield 結束", Padding);
}
Console.WriteLine("{0} Yielding最後一個值", Padding);
yield return -1;
Console.WriteLine("{0} CreateEnumerable()方法結束", Padding);
}
static void Main(string[] args)
{
IEnumerable<Int32> iterable = CreateEnumerable();
IEnumerator<Int32> iterator = iterable.GetEnumerator();
Console.WriteLine("開始迭代");
while (true)
{
Console.WriteLine("調用MoveNext方法……");
Boolean result = iterator.MoveNext();
Console.WriteLine("MoveNext方法返回的{0}", result);
if (!result)
{
break;
}
Console.WriteLine("獲取當前值……");
Console.WriteLine("獲取到的當前值爲{0}", iterator.Current);
}
Console.ReadKey();
}
}
------------------------------------------------------------------------------------------
public class List
{
//using System.Collections;
public static IEnumerable Power(int number, int exponent)
{
int counter = 0;
int result = 1;
while (counter++ < exponent)
{
result = result * number;
yield return result;
}
}
static void Main()
{
// Display powers of 2 up to the exponent 8:
foreach (int i in Power(2, 8))
{
Console.Write("{0} ", i);
}
}
}