List<>.Find() 使用Anonymous Delegate
在.NET 2.0之後開始支援了泛型,而且許多集合類別中也都支援了許多泛型函式。例如List<>中可以使用Find()函式來搜尋在List集合中的資料,將符合搜尋條件的資料給搜尋出來。
雖然List<>.Find()函式定義了要傳入的參數型別:Predicate,可是在實作上其實有許多種不同的方式。每種方式都有其優缺點,在此針對這些方式提供筆者個人的一些看法給大家參考。
首先先來看一段程式碼:
在上面這段程式碼中,筆者用了三種方式來查詢List<>集合中的資料,這三種方式分別是:
雖然List<>.Find()函式定義了要傳入的參數型別:Predicate
首先先來看一段程式碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TestVS2008 { public class AnonyDelegate { public void Test() { List<string> listData = new List<string>(); listData.Add("Eric"); listData.Add("Anny"); listData.Add("Sophia"); string target = "Anny"; // Search string found = listData.Find( IsMatch ); Console.WriteLine("Search with Predicate function : " + found); // Search with SearchFunctor found = listData.Find(new SearchFunctor(target).SearchPredicate); Console.WriteLine("Search with SearchFunctor : " + found); // Search with anonymous delegate found = listData.Find(delegate(string str) { return target == str; }); Console.WriteLine("Search with anonymous delegate : " + found); } protected bool IsMatch(string str) { return str == "Anny"; } protected class SearchFunctor { protected string target = ""; public SearchFunctor(string target) { this.target = target; } public bool SearchPredicate(string str) { return str == target; } } } }
在上面這段程式碼中,筆者用了三種方式來查詢List<>集合中的資料,這三種方式分別是:
- 用一般的函式來作為Predicate
所需的查詢函式 - 用一個查詢函式類別(SearchFunctor)來提供Predicate
所需的查詢函式 - 用匿名委派函式來提供Predicate
所需的查詢函式
在第一種方式中,可以看到我們想要查詢的目標字串,必須寫死在這個查詢函式中,因為這個查詢函式所能接收的參數個數只有一個,就是在被List.Find() 呼叫時所使用的比較對象。所以在使用上,外部的人無法再指定要查詢的目標。
為了解決無法指定查詢目標的問題,筆者第二種方式就改成提供一個查詢函式類別(SearchFunctor)來提供查詢的功能。這種方式的確是可以查詢出指定的目標,不過,感覺上是要多定義出一個類別來供其它人使用。
一開始是有想過使用匿名函式,只是想說匿名函式也是要符合List.Find()中的Predicate函式的定義,也就是只能接收List所傳入要進行比較的對象,無法指定要查詢的目標。所以才想到要定義一個查詢函式類別。不過,後來想到,其實匿名函式的程式碼也是存活在要使用的函式碼區段中,理應可以使用在這段程式碼中的變數。
為了避免多定義一種類別,筆者就試著改用匿名函式來改寫。所以就像第三種方式那樣,在匿名函式的函式定義中,可以使用到外部可存取到的變數。
乍看之下使用匿名函式似乎比較有效率。不過試想一下,如果這段匿名函式中的Predicate函式的實作是比較複雜的話,那每次要使用的人,就必須再自行寫一段同樣的程式碼。那勢必會造成程式碼重複的問題,維護上會有其困難度。
所以,如果實作Predicate的函式內容是比較簡單的話,那建議就使用匿名函式。反之,如果實作的程式碼是比較複雜的話,那建議就用第二種方式,寫成一個類別,以便重複使用。
* 2010/4/1 補充
有聽到有人說,當使用Find()時要搜尋某個目標值,而在給定的List<>等集合中有同時存在一個以上的目標值時,會出現Exception。這表示在搜尋時,.NET會整個掃過所有集合中的元素?如果這樣的話,真的太沒效率。所以我測試了一下,發現並不會出現任何Exception。它會傳回第一個找到的元素。
留言
張貼留言