前言
使用linq的時候大家應(yīng)該都知道IEnumerable和IEnumerator接口!
解釋一下
IEnumerable 它利用 GetEnumerator() 返回 IEnumerator 集合訪問器,聲明實現(xiàn)該接口的class是“可枚舉(enumerable)”的 通俗點說就是可進行迭代操作的類型瞎颗。
IEnumerator解釋:它是一個的集合訪問器旺入,使用foreach語句遍歷集合或數(shù)組時门怪,就是調(diào)用 Current坐梯、MoveNext()的結(jié)果郎汪。
例子
今天給大家講講迭代器的原理 我們自己實現(xiàn)一個UserInforMationList
我這里定義一個UserInforMationModel和UserInforMationList類
public class UserInforMationList
{
public UserInforMation[] _UserInforMations;
public void Add(UserInforMation[] userInforMations)
{
_UserInforMations = new UserInforMation[userInforMations.Length];
for (int i = 0; i < userInforMations.Length; i++)
{
_UserInforMations[i] = userInforMations[i];
}
}
}
{
public string UserName { get; set; }
public string Sex { get; set; }
}
使用我們的測試方法价卤,發(fā)現(xiàn)我們的代碼報錯了UserInforMationList不包含 GetEnumerator的公共實例劝萤,因此不能使用ForEach.
那么我們要怎么實現(xiàn)Foreach了那就要用到IEnumerator、IEnumerable!
提示告訴我們?nèi)鄙僖粋€GetEnumerator的公共實例
我們看下IEnumerable接口
{
[DispId(-4)]
[__DynamicallyInvokable]
IEnumerator GetEnumerator();
}
Enumerable接口剛好返回一個GetEnumerator 然后再看一下IEnumerator
IEnumerator接口為類內(nèi)部的集合提供了迭代方式慎璧, IEnumerator 要求你實現(xiàn)三個方法:
{
[__DynamicallyInvokable]
object Current
{
[__DynamicallyInvokable]
get;
}
[__DynamicallyInvokable]
bool MoveNext();
[__DynamicallyInvokable]
void Reset();
}
看了這兩個接口就可以知道我們的UserInforMationList:要繼承這個IEnumerable接口 這個接口返回的是一個GetEnumerator床嫌。觀察這方法,
{
throw new NotImplementedException();
}
需要返回一個叫做IEnumerator的接口胸私,因此厌处,一個類要想可迭代,還需要進一步實現(xiàn)IEnumerator類岁疼,這個才是真正獲取到的迭代器阔涉,
那我們再定義一個UserInforMationEnumerator繼承于GetEnumerator然后實現(xiàn)這三個方法,
- MoveNext方法:該方法將集合索引加1,并返回一個bool值瑰排,指示是否已到達集合的末尾贯要。
- Reset方法:它將集合索引重置為其初始值-1,這會使枚舉數(shù)無效椭住。
- Current方法: 返回position位置的當(dāng)前對象
{
public UserInforMation[] _userInforMations;
public int _Index = -1;
public UserInforMationEnumerator(UserInforMation[] userInforMations)
{
_userInforMations = userInforMations;
}
public object Current => _userInforMations[_Index];
public bool MoveNext()
{
_Index++;
return _Index < _userInforMations.Length;
}
public void Reset()
{
_Index = -1;
}
}
這樣我們就實現(xiàn)了自己的迭代器崇渗。
然后我們跑一下代碼
我們調(diào)用GetEnumerator的時候,看似里面for循環(huán)了一次京郑,其實這個時候沒有做任何操作宅广。只有調(diào)用MoveNext的時候才會對應(yīng)調(diào)用for循環(huán):
現(xiàn)在我想可以回答你為什么Linq to Object中要返回IEnumerable?:
因為IEnumerable是延遲加載的,每次訪問的時候才取值傻挂。也就是我們在Lambda里面寫的where乘碑、select并沒有循環(huán)遍歷(只是在組裝條件),只有在ToList或foreache的時候才真正去集合取值了金拒。這樣大大提高了性能兽肤。
最后大家如果喜歡我的文章,還麻煩給個關(guān)注并點個贊, 希望net生態(tài)圈越來越好绪抛!
微信公眾號:黑哥聊dotNet