簡單介紹一下linq,linq很多人其實用的很熟練了,但是有些人不知道自己用的是linq。
在介紹linq 之前,先介紹一下集合。
public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
int Count { get; }
bool IsReadOnly { get; }
void Add(T item);
void Clear();
bool Contains(T item);
void CopyTo(T[] array, int arrayIndex);
bool Remove(T item);
}
什麼是集合呢?在c# 中擁有上面功能的就是集合。
這裡面可以看到集合繼承了IEnumerable 這個介面。
繼承這個介面意味集合可以列舉的,也就是簡單來說可以遍歷的。
那麼c# 中的集合是否一定要繼承ICollection。
這個就不一定,比如說字典,字典在現實生活中明顯是一組集合吧,那麼在c# 中也應該是即可。
為什麼字典不繼承ICollection,原因也很簡單,因為void Add(T item); 對字典來說沒有意義。
字典是key 和 value 這種模式,ICollection 是無法滿足很多集合需求的,因為集合的多樣性太多了(非常豐富)。
那麼在c# 中什麼樣的是集合呢? 繼承IEnumerable的就是集合。
如果要資料初始化的話,那麼要增加Add方法。
public class TestCollection<T> : IEnumerable<T>
{
public void Add(T a)
{
}
public void Add(List<T> a)
{
}
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
這裡有兩個add,一個增加T,一個增加T列表。
internal class Program
{
static void Main(string[] args)
{
List<string> l = new List<string>() { "1", "2", "3"};
TestCollection<string> a = new TestCollection<string>()
{
"123",
l
};
}
}
這樣就ok了。
我們知道實現了Ienumerable的可以進行遍歷。
因為IEnumerable 返回了一個 IEnumerator
迭代器就是while,然後MoveNext,然後再Current,獲取資料。
這裡有些人可能會有一個很小的問題,那就是為什麼不直接實現迭代器,而是有一個IEnumerable,裡面有一個IEnumerator GetEnumerator();。
原因很簡單,因為遍歷每次都是從頭開始,都是一個新的開始。
因為IEnumerator 繼承 IDisposable, 如果需要每次遍歷完做某些事情的話,可以放在IEnumerator的void Dispose();中實現。
所以foreach 實際上是幹了這樣一件事。
那麼foreach 是否一定要繼承IEnumerable 呢? 這個不一定。
foreach 採用一個duck typing的這種方式,duck typing是什麼意思呢?就是走起來想一隻鴨子,然後叫起來像一隻鴨子,那麼就是鴨子。
只要有GetEnumerator就行:
internal class Program
{
static void Main(string[] args)
{
List<string> l = new List<string>() { "1", "2", "3"};
TestForeach<string> a = new TestForeach<string>();
foreach (var b in a)
{
}
}
}
public class TestForeach<T>
{
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
}
在foreach 迴圈中不能進行賦值。
同樣在foreach 迴圈中不能對集合的個數進行修改。
無論是增加還是刪除list的version都會發生變化。
很多書裡面介紹了,為什麼不能複製和增加集合個數,這樣會使人頭腦不清醒。
因為這是遍歷,應該是一個原子,這樣的設計不會新增歧義性,單一職責邏輯清晰能減少不必要的bug。
一般來說都會繼承一下IEnumerable 這個介面。 為什麼呢?因為linq。
linq 是 language integated query,語言整合查詢。
也就是說定義了一套規範哈,對於我們來說其實不用太在意這個規範是什麼,大體看一下就行。
對IEnumerable而言,實現的就在system.IEnumberable.linq 上面,參照用就好。
然後linq有一個很大的特點,就是延遲執行。
然後來說下這個延遲執行是怎麼實現的哈。
比如我們的list 經過where 之後,其實在執行時就不是linq。
執行時是這個型別WhereListIterator。
就看個list的。
執行where 其實就是把list 給 WhereListIterator。
並沒有生成新的list,所以說不會執行where操作。
當遍歷的時候就會執行WhereListIterator的movenext。
遍歷的時候就會做條件判斷。
所以呢,如果進行多次遍歷後呢,其實一直都在執行你的where 語句。
如果需要遍歷多次,where 迴圈後,最好直接tolist轉換成一個list。
當然有興趣可以去看下其他的,這裡只是舉個例子,其實就是用包裝器模式實現的。
這樣經過層層包裝,人們就會想啊,如果where 語句按照順序執行,那麼不會很慢啊。
所以linq還可以並行實現,使用asParallel(),這個東西來實現。
這樣執行就是並行的, 先不管實現,並行篇會介紹,只需要知道官方幫我們實現了,這樣執行更快就可以了。
因為東西比較多,下一節是一些複雜的linq和匿名linq,下下節是查詢表示式。 linq 是實現其實很複雜,但是用起來是真的簡單。