System.Linq.Enumerable類,提供了數十種稱為擴展方法的共享方法,幫助您操作所有實現IEnumerable(of T)接口的類中的數據。由於Enumerable類的擴展方法可以處理許多其他類如(包括Array和List),因此不僅可以使用Enumerable類的方法來創建LINQ查詢,還可以用它來操作數組和其他數據結構的行為。
查看Enumerable類擴展方法的文檔,你會發現每個成員都為Shared。因此可以通過兩種方案來調用方法。
第一種方案:按照聲明類型的方法來調用,即傳入擴展類的實例
Dim itemcount = Enumerable.Count(query, Function(prod) prod.Equals("Chang"))
第二種方案:想操作集合本身的實例方法一樣,調用擴展方法,不必提供第一個參數
Dim itemCount1 = queryAgain.Count(Function(qS) qS.Equals("Chang"))
從經過排序的數據中取得前10項,擴展方法Take:從序列的開頭返回指定數量的連續元素。
Dim query = _ db.Products.Where(Function(product) product.CategoryId = 1) _ .OrderBy(Function(product) product.ProductName) _ .Select(Function(product) product.ProductName) _ .Take(10)
創建序列
Enumerable類提供了多個shared方法,但他們不是擴展方法,我們先從這些簡單的方法開始。
Enumerable.Range
Enumerable.Range方法創建一個新的整數有序列表。可指定列表的起始值和項目數。此方法將返回一個IEnumerable(of Integer)序列。下面代碼,使用Range方法填充列表,然后使用一個簡單的lambda表達式調用Enumerable.orderby方法,按隨機順序排列序列。
Dim rad As New System.Random Dim items = Enumerable.Range(1, 10) Dim randomList = items.OrderBy(Function() rad.Next())
多次運行代碼時,每次返回不同的結果。
Enumberable.Reverse
Enumberable.Reverse方法以相反順序返回輸入序列。
Dim items = Enumerable.Range(1, 10) Dim reversed = items.Reverse()
Enumerable.Repeat
Enumerable.Repeat方法創建包括指定值,且按指定次數重復的一個列表。
Dim repeated = Enumerable.Repeat("Hello", 6)
執行代碼后,repeated變量為
Hello, Hello, Hello, Hello, Hello, Hello
選擇序列
Enumerable.select
Enumerable.select方法將每個元素投影成新的格式。
Dim db As New SimpleDataContext Dim results = db.Customers.Where(Function(customer) customer.Country = "USA") _ .Select(Function(customer, index) _ String.Format("{0}.{1}", index + 1, customer.ContactName))
Enumerable.selectMany
Enumerable.selectMany方法獲取一個項目集合,其中的每個項目可能又是一個項目集合,然后將兩維輸入縮成一維輸出序列。例如,如果需要獲取種類列表,每個種類又包括多個產品,並最終得到具有對應種類信息的產品列表,此方法會非常有用。
Dim db As New SimpleDataContext Dim categories = db.Categories _
.Where(Function(category) category.Products.Count < 7) Dim reuslts = categories.SelectMany( _ Function(category, index) category.Products.Select( _ Function(product) String.Format("{0}.Category {1}:{2}", _ index, product.CategoryId, product.ProductName)))
在此示例中,傳到selectMany方法的lambda表達式接受對特定種類的引用(依次處理每個種類)。selectMany方法的這一特定重載將種類的索引以及種類一起傳遞給 lambda 表達式。有了種類及其索引后,lambda 表達式將針對種類的 Products 屬性調用 Select 方法,允許它處理種類中的每個產品。此示例返回包含以下字符串列表的一個序列。調用 SelectMany 將原始種類/產品層次結構平鋪成單個值列表。
檢索單個元素
你常常會需要檢索和處理序列中的單個元素。Enumerable類提供了多種方法來將序列內容篩選成單個元素。
Enumerable.First、Enumerable.Last
Enumerable.first和Enumerable.last方法分別返回序列中的第一個和最后一個元素。
Enumerable.Single
給定指定單個元素的函數或者Lambda表達式后,Enumerable.Single方法將返回一個元素。
Enumerable.ElementAt
Enumerable.ElementAt方法將返回位於序列中特定索引位置的一個元素。
如果序列中並不存在請求的元素(對於Single方法而言,如果限制條件導致出現零個元素或多個元素),上述每種方法都會拋出異常。它們還允許指定一個lambda表達式或函數來限制輸入數據。在任何情況下,結果序列必須包含一個元素。
Enumerable 類還提供類似方法,它在條件允許時返回單個元素,否則返回序列類型的默認成員。這些方法是 Enumerable.FirstOrDefault、Enumerable.LastOrDefault、Enumerable.SingleOrDefault 和 Enumerable.ElementAtOrDefault。
篩選序列
Enumerable.where、Enumerable.Distinct或者Enumerable.OfType方法篩選現有序列的內容,即可返回輸出序列中原始數據的子集。
Enumerable.OfType
Enumerable.OfType方法基於指定類型篩選輸入序列。假設希望僅針對窗體上特定類型的控件執行操作。通過使用OfType方法,可以限制窗體公開的控件集合並僅遍歷相關的控件子集。
Dim items As New List(Of Object) items.Add("January") items.Add(0) items.Add("Monday") items.Add(3) items.Add(5) items.Add("September") Dim numbers = items.OfType(Of Integer)() Dim strings = items.OfType(Of String)()
代碼運行后的,兩個輸出列表,包含以下數據:
0, 3, 5 January, Monday, September
Enumerable.Where
Enumerable.where方法允許指定篩選輸入序列的條件。第二個重載版本可訪問集合中每個項目的索引,以便根據索引執行篩選。
Dim files As IEnumerable(Of FileInfo) = _ New DirectoryInfo("C:\Windows").GetFiles() Dim fileResults = _ files.Where(Function(file) file.Length < 100) _ .Select(Function(file) String.Format("{0} ({1})", file.Name,file.Length))
上面代碼中,New DirectoryInfo("C:\Windows").GetFiles()返回的是,System.IO.FileInfo 類型數組。由於數組實現了IEnumerable接口,因此可使用where方法篩選數組內容。
fileResults = _ files.Where(Function(file, index) ((file.Length < 100) And (index < 20))) _ .Select(Function(file) String.Format("{0} ({1})", file.Name, file.Length))
Enumerable.Distinct
Enmerable.Distinct方法可篩選列表,使輸出序列僅包含輸入列表中單獨存在的項目。對應簡單的值(字符串、數字等),此過程非常簡單。
對於復雜對象列表,運行時引擎如何才能通過比較確定兩個對象是否重復?無法簡單地比較實例變量,這一點與在實際操作中僅比較對象的地址不同。對於復雜對象,必須提供一個比較器,即實現IEqualityComparer(Of T)執行比較。
