如果大家讀過dapper源碼,你會發現這內部有很多方法都用到了yield關鍵詞,那yield到底是用來幹嘛的,能不能拿掉,拿掉與不拿掉有多大的差別,首先上一段dapper中精簡後的Query方法,先讓大家眼見為實。 一:yield探究 1. 骨架代碼猜想 骨架代碼其實很簡單,方法的返回值是IEnum ...
如果大家讀過dapper源碼,你會發現這內部有很多方法都用到了yield關鍵詞,那yield到底是用來幹嘛的,能不能拿掉,拿掉與不拿掉有多大的差別,首先上一段dapper中精簡後的Query方法,先讓大家眼見為實。
private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefinition command, Type effectiveType)
{
object param = command.Parameters;
var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param?.GetType());
var info = GetCacheInfo(identity, param, command.AddToCache);
IDbCommand cmd = null;
IDataReader reader = null;
bool wasClosed = cnn.State == ConnectionState.Closed;
try
{
while (reader.Read())
{
object val = func(reader);
if (val == null || val is T)
{
yield return (T)val;
}
else
{
yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);
}
}
}
}
一:yield探究
1. 骨架代碼猜想
骨架代碼其實很簡單,方法的返回值是IEnumerable
2. msdn解釋
有自己的猜想還不行,還得相信權威,看msdn的解釋:https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/yield
如果你在語句中使用 yield 上下文關鍵字,則意味著它在其中出現的方法、運算符或 get 訪問器是迭代器。 通過使用 yield 定義迭代器,可在實現自定義集合類型的 IEnumerator
沒用過yield之前,看這句話肯定是一頭霧水,只有在業務開發中踩過坑,才能體會到yield所帶來的快感。
3. 從IL入手
為了方便探究原理,我來寫一個不能再簡單的例子。
public static void Main(string[] args)
{
var list = GetList(new int[] { 1, 2, 3, 4, 5 });
}
public static IEnumerable<int> GetList(int[] nums)
{
foreach (var num in nums)
{
yield return num;
}
}
對,就是這麼簡單,接下來用ILSpy反編譯打開這其中的神秘面紗。
從截圖中看最讓人好奇的有兩點。
<1> 無緣無故的多了一個叫做<GetList>d__1 類
好奇心驅使著我看一下這個類到底都有些什麼?由於IL代碼太多,我做一下精簡,從下麵的IL代碼中可以發現,果然是實現了IEnumerable介面,如果你瞭解設計模式中的迭代器模式,那這裡的MoveNext,Current是不是非常熟悉?