標籤:blog http 使用 io 資料 for 2014 ar
在 OOPL 中,有靜態方法、執行個體方法和虛方法,如下: public sealed class String{ public static bool IsNullOrEmpty(string s) { // ... } public string Replace(string old, string new) { // ... }}public abstract class Stream{ public virtual void WriteByte(byte value) { // ... }} 其中,IsNullOrEmpty 是靜態方法,Replace 是執行個體方法,而 WriteByte 就是虛方法。其用法如下: String name = null;Console.WriteLine(String.IsNullOrEmpty(name)); // true String s = "Hello, world!";Console.WriteLine(s.Replace("world", "C#")); // Hello, C#! 虛方法需要在匯出類(derived class)中重新定義,此處不贅。 而在 C# 3.0 中,又引入了一種方法,稱為 擴充方法(Extension Method): Extension methods allow an exsting type to be extended with new methods without altering the definition of the original type.擴充方法是用新方法來擴充原有類型,而不用修改原有類型的定義。 擴充原有類型(Extending the existing type) 擴充原有類型的機制(手段)有類的繼承,還有 C# 中的擴充方法。 類的繼承通過增加新成員,可以擴充原有類型的資料成員(fields);可以定義新方法或重寫被繼承類的虛方法來擴充原有類型的方法成員(methods)。但繼承機制也存在自己的問題,如果原有型別宣告為封閉類型(sealed class),則無法使用繼承機制擴充原有類型(如上述的 String class)。再者,匯出類(derived class)對基類(base class)的擴充是作用在匯出類上的,而非對基類自身的擴充。 擴充方法彌補了繼承機制的不足。嚴格說來,擴充方法不是語言本身的機制,而是通過編譯器實現的文法便用設施。不管原有類型是封閉類型還是開放類型,都可以用擴充方法進行擴充。擴充方法只是擴充原有類的方法成員,並不能擴充原有類的資料成員。 An extension method is a static method of a static class, where the this modifier is applied to the first parameter. The type of the first parameter will be the type that is extended.擴充方法是靜態類的靜態方法,其第一個參數要用 this 修飾,而這第一個參數的類型就是要擴充的類型。 例子: public static class StringHelper{ public static bool IsCapitalized(this string s) { if (string.IsNullOrEmpty(s)) return false; return char.IsUpper(s[0]); }} IsCapitalized 就是定義在靜態類上的靜態方法,而其第一個參數 string s 用 this 修飾,所以 IsCapitalized 是擴充方法,因為第一個參數的類型是 string,所以 IsCapitalized 擴充的是 string 類型。 用法: Console.WriteLine("Perth".IsCapitalized()); "Perth".IsCapitalized() 是直接針對 string "Perth" 調用 IsCapitalized(),因為 IsCapitalized() 是 string 的擴充方法,所以這種調用是可以的。 擴充方法的調用經過編譯器的解析後,就翻譯為普通的靜態方法調用,即: Console.WriteLine(StringHelper.IsCapitalized("Perth")); 而 "Perth".IsCapitalized() 相對於 StringHelper.IsCapitalized("Perth") 而言,更為自然、簡潔。 所以,擴充方法仍然是一種靜態方法,只是 C# 語言引入的文法便用設施而已。編譯器的翻譯過程如下: arg0.Method(arg1, arg2, ...); ==> StaticClass.Method(arg0, arg1, arg2, ...); 也就是將擴充方法調用翻譯為普通的靜態方法調用。 擴充方法的應用 string 類雖然提供了功能強大的眾多方法,但總是不可能滿足所有需求。有些經常使用而 string 類又沒有提供的功能,可以寫成擴充方法,並歸入程式碼程式庫(Library),可以再多重專案中使用。下面是一個例子,兩個有關 string 的擴充方法,放入 StringExtensions 類中: public static class StringExtensions
{
public static List<KeyValuePair<string, string>> Listize(this string ss)
{
List<KeyValuePair<string, string>> pList = new List<KeyValuePair<string, string>>();
string[] slist = ss.Split(new char[] { ‘;‘ });
foreach (string s in slist)
{
if (string.IsNullOrEmpty(s)) continue;
string[] pair = s.Split(new char[] { ‘:‘ });
if (pair.Length != 2) continue;
pList.Add(new KeyValuePair<string, string>(pair[0], pair[1]));
}
return pList;
}
public static string MatchAndReplace(this string src, string pattern, string dst)
{
List<string> mList = new List<string>();
foreach (Match m in Regex.Matches(src, pattern))
{
mList.Add(m.Value);
}
foreach (string s in mList)
{
if (string.IsNullOrEmpty(s)) continue;
src = src.Replace(s, dst);
}
return src;
}
} 上述兩個擴充方法的用例如下: string sql = GetSQL(); string whereTail = "";
foreach (string k in po.CustomObject.Keys)
{
if (string.IsNullOrEmpty(k)) continue;
if (string.Compare(k, "DemoZoneList", true) == 0)
{
whereTail = po.CustomObject[k].Value.Listize().BuildWhereClauseInclusive();
}
else if (string.Compare(k, "NonDemoZoneList", true) == 0)
{
whereTail = po.CustomObject[k].Value.Listize().BuildWhereClauseExclusive();
}
}
if (!string.IsNullOrEmpty(whereTail))
{
sql = sql.MatchAndReplace("1[ ]*=[ ]*1", whereTail);
} 可以看到,string 的擴充方法就像原生方法(指 String 類定義的方法)一樣調用,代碼看起來更加自然、簡潔。 擴充方法機制是為瞭解決 LINQ 的問題而引入的,關於這一點,當另文別述。關於擴充方法的深入討論,可以參閱《C# in Depth》 Third Edition。