yield 關鍵字向編譯器指示它所在的方法是迭代器塊。 編譯器生成一個類來實現迭代器塊中表示的行爲。 在迭代器塊中,yield 關鍵字與 return 關鍵字結合使用,向枚舉器對象提供值。 這是一個返回值,例如,在 foreach 語句的每一次循環中返回的值。 yield 關鍵字也可與 break 結合使用,表示迭代結束。 有關迭代器的更多信息,請參見迭代器(C# 編程指南)。 下面的示例演示兩種形式的 yield 語句。html
yield return <expression>;
yield break;
在 yield return 語句中,將計算 expression 並將結果以值的形式返回給枚舉器對象;expression 必須能夠隱式轉換爲 yield 類型的迭代器。express
在 yield break 語句中,控制權將無條件地返回給迭代器的調用方,該調用方爲枚舉器對象的 IEnumerator.MoveNext 方法(或其對應的泛型 System.Collections.Generic.IEnumerable<T>)或 Dispose 方法。編程
yield 語句只能出如今 iterator 塊中,這種塊可做爲方法、運算符或訪問器的主體實現。 這類方法、運算符或訪問器的體受如下約束的控制:安全
-
不容許不安全塊。app
-
方法、運算符或訪問器的參數不能是 ref 或 out。ide
-
yield return 語句不能放在 try-catch 塊中的任何位置。 該語句可放在後跟 finally 塊的 try 塊中。函數
-
yield break 語句可放在 try 塊或 catch 塊中,但不能放在 finally 塊中。oop
yield 語句不能出如今匿名方法中。 有關更多信息,請參見 匿名方法(C# 編程指南)。post
當和 expression 一塊兒使用時,yield return 語句不能出如今 catch 塊中或含有一個或多個 catch 子句的 try 塊中。 有關更多信息,請參見 異常處理語句(C# 參考)。ui
在下面的示例中,迭代器塊(這裏是方法 Power(int number, int power))中使用了 yield 語句。 當調用 Power 方法時,它返回一個包含數字冪的可枚舉對象。 注意 Power 方法的返回類型是 System.Collections.IEnumerable(一種迭代器接口類型)。
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);
}
}
}
/*
Output:
2 4 8 16 32 64 128 256
*/
有關更多信息,請參見 C# 語言規範。C# 語言規範是 C# 語法和用法的權威資料。
C# yield return 用法與解析
本文參考自:http://www.jb51.net/article/54810.htm
當初沒有認真理解 yield 這個關鍵字,如今又遇到了依舊不理解,爲了之後再也不爲了 yield 困惑,決定好好研究一下 yield 的用法與意義:
yield 從字面上理解有「退位,屈服」的意思,轉一下彎就理解成「權限轉移」,也就是將控制權交給別人,在這裏就是把集合裏知足條件(若是沒有過濾條件,就是全體)的個體的操做轉移給另外一個對象。
class Program { static void Main(string[] args) { foreach (var item in FilterWithoutYield) { Console.WriteLine(item); } Console.ReadKey(); } //申明屬性,定義數據來源
public static List<int> Data { get { return new List<int>(){1,2,3,4,5,6,7,8}; } } //申明屬性,過濾器(不適用yield)
public static IEnumerable<int> FilterWithoutYield { get { var result = new List<int>(); foreach (var i in Data) { if (i > 4) result.Add(i); } return result; } } }
能夠看到若是不用yield,要返回大於4的全部的數,就要到另外一個集合。而用yield的狀況下就沒必要如此麻煩了:
//申明屬性,過濾器(使用yield)
public static IEnumerable<int> FilterWithoutYield { get { foreach (var i in Data) { if (i > 4) yield return i; } } }
爲何會這樣呢?
經過單步調試發現:
雖然2種方法的輸出結果是同樣的,但運做過程迥然不一樣。第一種方法,是把結果集所有加載到內存中再遍歷;第二種方法,客戶端每調用一次,yield return就返回一個值給客戶端,是"按需供給"。
第一種方法,客戶端調用過程大體爲:
使用yield return,客戶端調用過程大體爲:
使用yield return爲何能保證每次循環遍歷的時候從前一次中止的地方開始執行呢?
--由於,編譯器會生成一個狀態機來維護迭代器的狀態。
簡單地說,當但願獲取一個IEnumerable<T>類型的集合,而不想把數據一次性加載到內存,就能夠考慮使用yield return實現"按需供給"。
============================================================================================
yield是C#爲了簡化遍歷操做實現的語法糖,咱們知道若是要要某個類型支持遍歷就必需要實現系統接口IEnumerable,這個接口後續實現比較繁瑣要寫一大堆代碼才能支持真正的遍歷功能。舉例說明
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
namespace
{
class Program
{
static void Main(string[] args)
{
HelloCollection helloCollection = new HelloCollection();
foreach (string s in helloCollection)
{
Console.WriteLine(s);
}
Console.ReadKey();
}
}
//
public class HelloCollection : IEnumerable
//
{
//
public IEnumerator GetEnumerator()
//
{
//
yield return "Hello";
//
yield return "World";
//
}
//}
public class HelloCollection : IEnumerable
{
public IEnumerator GetEnumerator()
{
Enumerator enumerator = new Enumerator(0);
return enumerator;
}
public class Enumerator : IEnumerator, IDisposable
{
private int state;
private object current;
public Enumerator(int state)
{
this.state = state;
}
public bool MoveNext()
{
switch (state)
{
case 0:
current = "Hello";
state = 1;
return true;
case 1:
current = "World";
state = 2;
return true;
case 2:
break;
}
return false;
}
public void Reset()
{
throw new NotSupportedException();
}
public object Current
{
get { return current; }
}
public void Dispose()
{
}
}
}
}
上面註釋的部分引用了"yield return」,其功能至關於下面全部代碼!能夠看到若是不適用yield須要些不少代碼來支持遍歷操做。
yield return 表示在迭代中下一個迭代時返回的數據,除此以外還有yield break, 其表示跳出迭代,爲了理解兩者的區別咱們看下面的例子
class A : IEnumerable
{
private int[] array = new int[10];
public IEnumerator GetEnumerator()
{
for (int i = 0; i < 10; i++)
{
yield return array[i];
}
}
}
若是你只想讓用戶訪問ARRAY的前8個數據,則可作以下修改.這時將會用到yield break,修改函數以下
public IEnumerator GetEnumerator()
{
for (int i = 0; i < 10; i++)
{
if (i < 8)
{
yield return array[i];
}
else
{
yield break;
}
}
}
這樣,則只會返回前8個數據.
出處:http://www.cnblogs.com/kingcat/archive/2012/07/11/2585943.html
static void Main(string[] args)
{
// Display the even numbers.
Console.WriteLine("Even numbers");
foreach (int i in GetEven())
Console.WriteLine(i);
Console.WriteLine("===================");
// Display the odd numbers.
Console.WriteLine("Odd numbers");
foreach (int i in GetOdd())
Console.WriteLine(i);
//aa();
//kk();
Console.ReadKey();
}
public static int[] ints = { 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377 };
public static IEnumerable<int> GetEven()
{
foreach (var item in ints)
if (item % 2 == 0)
yield return item;
}
public static IEnumerable<int> GetOdd()
{
foreach (var item in ints)
if (item % 2 == 1)
yield return item;
}