新Orcas語言特性:擴展方法 爲程序擴展方法

 

【原文地址】New "Orcas" Language Feature: Extension Methods
【原文發表日期】 Tuesday, March 13, 2007 2:27 AM

上個星期,我發表了我準備寫的討論一些新的VB和C#語言特性的系列博客貼子的第一篇,這些新語言特性是將於今年晚些時候發佈的Visual Studio和.NET框架Orcas版的一部分。

我的上一個博客貼子討論了自動屬性,對象初始化器和集合初始化器等新特性。如果你還沒有讀過這個帖子的話,請在這裏閱讀。今天的貼子討論一個VB和C#中都具有的,重要得多的新特性:擴展方法 (Extension Methods)

什麼是擴展方法 (Extension Methods)?

擴展方法允許開發人員往一個現有的CLR類型的公開契約(contract)中添加新的方法,而不用生成子類或者重新編譯原來的類型。擴展方法有助於把今天動態語言中流行的對duck typing的支持之靈活性,與強類型語言之性能和編譯時驗證融合起來。

擴展方法促成了好多有用的使用場景,並使在作爲Orcas一部分發布的.NET版本中引進的非常強大的LINQ查詢框架成爲可能。

簡單的擴展方法例子:

有沒有想過要檢查一個字符串變量是否是個合法的電子郵件地址? 在今天,你大概需要通過調用一個單獨的類(或許通過一個靜態方法)來實現檢查該字符串變量是否合法。譬如,象這樣:

 

string email Request.QueryString["email"];

if 
( EmailValidator.IsValid(email) ) {
   

}

 

而使用C#和VB中的新“擴展方法”語言特性的話,我則可以添加一個有用的“IsValidEmailAddress()”方法到string類本身中去,該方法返回當前字符串實例是否是個合法的字符串。然後我可以把我的代碼重寫一下,使之更加乾淨,而且更具描述性,象這樣:

 

string email Request.QueryString["email"];

if 
( email.IsValidEmailAddress() ) {
   

}

 

我們是怎麼把這個新的IsValidEmailAddress()方法添加到現有的string類裏去的呢?我們是通過定義一個靜態的類型,帶有我們的“IsValidEmailAddress”這個靜態的方法來實現的,象下面這樣:

 

public static class ScottGuExtensions
{
    
public static bool IsValidEmailAddress(this string s)
    {
        Regex regex 
= new Regex(@"^[/w-/.]+@([/w-]+/.)+[/w-]{2,4}$");
        return 
regex.IsMatch(s);
    
}
}

 

注意,上面的靜態方法在第一個類型是string的參數變量前有個“this”關鍵詞,這告訴編譯器,這個特定的擴展方法應該添加到類型爲“string”的對象中去。然後在IsValidEmailAddress()方法實現裏,我可以訪問調用該方法的實際string實例的所有公開屬性/方法/事件,取決於它是否是合法電子郵件地址來返回true/false。

在我的代碼裏把這個特定的擴展方法的實現添加到string實例,我只要使用標準的“using”語句來引入含有該擴展方法的實現的命名空間:

 

using ScottGuExtensions;

 

然後編譯器就會在任何string上正確地定位IsValidEmailAddress()方法。在公開發行的Orcas三月份的CTP中的C#和VB在Visual Studio代碼編輯器裏對擴展方法提供了完整的intellisense支持。所以,當我在一個字符串變量上點擊“.”關鍵詞時,我的擴展方法現在就會出現在intellisense的下拉框裏:

VB和C#編譯器也會很自然地給與你對所有擴展方法用法的編譯時的檢查,這意味着你會得到一個編譯時錯誤,假如你鍵錯或者錯用一個擴展方法的話。

[感謝David Hayden是他在去年的一個老帖子 裏第一個示範了我在上面使用的這個IsValidEmailAddress使用場景。]

擴展方法使用場景續...

利用擴展方法這個新特性來給個別類型添加方法給開發人員開闢了許多有用的擴展性使用場景。但使得擴展方法非常強有力的是,它們不僅能夠應用到個別類型上,也能應用到.NET框架中任何基類或接口上。這允許開發人員建立種種可用於整個.NET框架的豐富的可組合的框架層擴展。

譬如,考慮這樣一個場景,我想要一個既容易,描述性又強的方式來檢查一個對象是否已經包含在一個對象集合或數組裏。我可以定義一個簡單的.In(集合)擴展方法,我想把它添加到.NET框架中的所有對象上,我可以在C#裏這麼來實現這個“In()”擴展方法:

注意上面我是如何聲明擴展方法的第一個參數的:“this object o”。這表明,這個擴展方法應該適用於繼承於基類System.Object的所有類型,這意味著我可以在.NET中的每個對象上使用它。

上面這個“In”方法的實現允許我檢查一個指定的對象是否包含在作爲方法參數傳入的一個IEnumerable序列中。因爲所有的.NET集合和數組都實現了IEnumerable接口,現在我擁有了一個有用的,描述性強的方法來檢查一個任意的對象是否屬於任何.NET集合或數組。

然後我就可以使用這個“In()”方法來看一個特定的字符串是否在一個字符串數組中:

我也可以用它來檢查一個特定的ASP.NET控件是否在一個容器控件集合裏:

我甚至可以將其用在象整數這樣的標量數據類型上:

注意上面,你甚至可以在象整數值42這樣的基本數據類型值上使用擴展方法。因爲CLR支持數值類型的自動boxing/unboxing,擴展方法可以直接使用在數值和其他標量數據類型上。

你大概可以開始從上面的例子中看出,擴展方法可以促成一些非常豐富和描述性強的擴展性使用場景。當使用於.NET中常見的基類和接口上時,他們可以促成一些非常好的特定於某個領域(domain specific)的框架和組合使用場景。

內置的System.Linq擴展方法

一個在Orcas時段隨.NET發佈的內置的擴展方法庫是一套允許開發人員對任何數據進行查詢的非常強有力的查詢擴展方法。這些擴展方法實現位於新的 System.Linq 命名空間之下,定義了標準的查詢操作符擴展方法,可以爲.NET開發人員用來輕鬆地查詢XML,關係數據庫,.NET 對象, 和任何其他數據結構類型。

下面是使用這些查詢擴展方法的擴展性模型的幾個好處:

1) 它允許一個可用於所有數據類型(數據庫,XML文件,內存中的對象,以及web-services等)的共同的查詢編程模型和語法。

2) 它是可以組合的,允許開發人員輕鬆地往查詢語法中添加新的方法/操作符。譬如,我們可以將我們自定義的“In()”方法與爲LINQ所定義的標準的“Where()”方法作爲一個單獨查詢的一部分一起使用。我們自定義的In()方法看上去就跟由System.Linq命名空間提供的標準方法一樣。

3) 它是可擴展的,允許與任何數據提供器類型一起使用。譬如,任何一個象NHibernate或LLBLGen這樣現有的ORM引擎可以實現LINQ的標準查詢操作符來允許對他們現有的ORM實現和映射引擎實現LINQ查詢。這允許開發人員學會一個查詢數據的共同方式,然後對種類繁多的豐富數據存儲實現使用同樣的技能。

我將在下幾個星期裏對LINQ作更多的示範,但想留給你幾個例子,這些例子展示瞭如何對不同類型的數據使用幾個內置的LINQ查詢擴展方法:

使用場景一:對內存中的.NET對象使用LINQ擴展方法

假定我們象這樣定義了代表“Person”的類:

然後我可以使用新的對象初始化器和集合初始化器特性創建和填充一個“people”集合,象這樣:

然後我可以使用由System.Linq提供的標準的“Where()”擴展方法來獲取這個集合中FirstName的首字符是"S"的那些“Person”對象,象這樣:

上面這個新的 p => 語法是“Lambda表達式”的一個例子,是對C# 2.0匿名方法支持的更簡明的發展,允許我們通過一個實參來輕鬆地表達查詢過濾(在這個情形下,我們表示我們只想要返回一串firstname屬性的首字符是“S”字母的Person對象) 。上面這個查詢然後就會返回包含2個對象的序列,Scott 和 Susanne。

我也可以利用由System.Linq提供的新的“Average” 和“Max”擴展方法編寫代碼來決定我的集合裏的人的平均年齡,以及年齡最大的人,象這樣:

使用場景二:對XML文件使用LINQ擴展方法

你手工在內存裏創建一個硬寫(hard-coded)的數據集合大概是很少見的。更有可能的是,你會從一個XM文件,數據庫,或web服務裏獲取數據。

假定我們在硬盤上有一個XML文件,包含下面這樣的數據:

很明顯地,我可以使用現有的 System.Xml APIs 來裝載這個XML文件進一個DOM,然後訪問它,或者使用一個層次較低的XmlReader API ,自己對之手工分析。或者,在 Orcas中,我現在也可以使用支持標準的LINQ擴展方法的System.Xml.Linq 實現(即 XLINQ),更優雅地分析和處理XML。

下面的代碼例子展示瞭如何使用LINQ來獲取所有包含一個子節點的值的首字母爲“S”的<person> XML元素:

注意,它使用了跟內存中對象例子中一模一樣的 Where() 擴展方法。現在它返回一個“XElement”元素序列,XElemen是沒有類型的XML節點元素。或者我也可以重寫查詢表達式,通過LINQ的 Select() 擴展方法來構造數據形狀,提供一個使用了新的對象初始化器句法的Lambda 表達式來填充同樣的“Person”類,跟我們第一個內存中的集合的例子一樣:

上面的代碼會做需要打開,分析,和過濾XML,然後返回一個強類型的Person對象序列所有的工作,不需要什麼映射或持久的文件來映射數值,我只是在上面的LINQ查詢式裏直接指明瞭從XML到對象的構形而已。

我也可以和前面一樣使用同樣的Average() 和 Max() LINQ擴展方法來計算XML文件中<person>元素的平均年齡,以及最大年齡,象這樣:

我不用手工分析XML文件,XLINQ 不僅可以爲我處理分析,它在估算LINQ表達式時,也可以使用低層的XMLReader,而不是使用DOM來分析文件。這意味着它是迅速之極,而且不分配很多內存。

使用場景三:對數據庫使用LINQ擴展方法

假定我們擁有一個SQL數據庫,內含一個叫“People”的表,具有下列數據定義:

我可以使用Visual Studio中新的LINQ到SQL的所見即所得(WYSIWYG) ORM設計器,快速地創建一個映射到數據庫的“Person”類:

然後我可以使用我先前用於對象和XML文件同樣的LINQ Where() 擴展方法,從數據庫中獲取firstname的首字符爲“S”的強類型“Person”對象序列:

注意,查詢句法與對象和XML場景中的一模一樣。

然後我也可以使用與前面一樣的 LINQ Average() 和Max() 擴展方法來從數據庫裏獲取平均和最大值,象這樣:

要使上面代碼例子工作,你自己不需編寫任何SQL代碼。Orcas中提供的LINQ到SQL對象關係映射器會處理獲取,跟蹤,和更新映射到你的數據庫數據定義和存儲過程的對象。你只要使用任何LINQ擴展方法對結果進行過濾和構形即可,LINQ到SQL會執行獲取數據所需的SQL代碼(注意,上面的 Average和Max 擴展方法很明顯地不會從數據表中返回所有的數據行,它們會使用TSQL的聚合函數來計算數據庫中的值,然後只返回一個標量值)。

請觀看我一月份製作的一個錄像,演示了LINQ到SQL如何顯著地改進了Orcas中的數據生產力。錄像中,你也可以看到新的LINQ到SQL的所見即所得ORM設計器的實戰示範,以及對數據模型編寫LINQ代碼時代碼編輯器提供的完整的 intellisense。

結語

希望上面的帖子給了你一個對擴展方法工作原理的基本理解,以及你能夠利用它們來實現的一些酷擴展性方式。跟任何擴展性機制一樣,我要告誡你別一開始就濫建新的擴展方法。不能因爲你有一個閃亮的新榔頭,就意味着世界上所有的東西突然都變成釘子了!

想着手開始嘗試擴展方法的話,我建議你先探究一下Orcas中System.Linq命名空間中提供的標準查詢操作符。這些操作符提供了對任何數組,集合,XML流,或關係數據庫做豐富的查詢的支持,可以極大地改進你操作數據時的生產力。我認爲你會發現它們極大地減小了你要在你應用中編寫的代碼量,允許你編寫非常乾淨和描述性強的語句。它們也允許你在你編碼中得到查詢邏輯自動的intellisense 和編譯時檢查。

在下幾個星期裏,我將繼續這個關於Orcas中新語言特性的系列,探討匿名類和類的推斷(Type Inference),還會討論Lambda的細節和其他酷特性。很明顯地,我還會地更多地討論LINQ。

希望本文對你有所幫助,

Scott

標籤: ASP.NET.NETLINQDataSQL Server

打印 | 張貼於 2007-04-07 02:38:00 | Tag:ASP.NET  .NET  LINQ  Data  SQL Server

留言反饋

[轉貼].NET3.5新特性,Lambda表達式 編輯
【原文地址】New
2008-02-13 21:01:00 | [匿名:菩提樹下的楊過]
VS2008學習之路 轉載 編輯
VS2008學習之路 轉載
2008-01-29 13:28:00 | [匿名:zym12021]
Visual Studio 2008 和 .NET 3.5 發佈了 編輯
【原文地址】VisualStudio2008and.NET3.5Released 【原文發表日期】Monday,November19,200710:34AM 今天我們發佈...
2008-01-25 19:33:00 | [匿名:宏宇]
新Orcas語言特性:擴展方法 編輯
新Orcas語言特性:擴展方法
2008-01-24 11:05:00 | [匿名:都市劍客]
VS 2008 和 .NET 3.5 Beta 2 發佈了 編輯
我非常高興地宣佈,VS 2008和.NET 3.5的Beta2版本可以下載了。你可以在這裏下載Visual Studio 2008產品。你也可以在這裏下載較小的VS 2008 Express版本。
2008-01-08 16:33:00 | [匿名:小魚兒]
Visual Studio 2008 和 .NET 3.5 發佈了 編輯
【原文地址】VisualStudio2008and.NET3.5Released 【原文發表日期】Monday,November19,200710:34AM 今天我們發佈...
2008-01-08 16:00:00 | [匿名:吳華朋]
ASP.NET MVC框架(第四部分): 處理表單編輯和提交場景 編輯
【原文地址】ASP.NETMVCFramework(Part4):HandlingFormEditandPostScenarios 【原文發表日期】Sunday,Decem...
2008-01-05 08:47:00 | [匿名:幸福]
Visual Studio 2008 和 .NET 3.5 發佈了 編輯
【原文地址】VisualStudio2008and.NET3.5Released 【原文發表日期】Monday,November19,200710:34AM 今天我們發佈...
2008-01-05 08:43:00 | [匿名:幸福]
VS2008學習之路 編輯
[1]新的C#語言特性:自動屬性(AutomaticProperties) public
2008-01-04 09:40:00 | [匿名:大力bober]
VS2008學習之路 編輯
[1]新的C#語言特性:自動屬性(AutomaticProperties) public
2008-01-02 15:51:00 | [匿名:大力bober]
回覆: 新Orcas語言特性:擴展方法 編輯
強! 

正在搞.NET3.5
2008-01-02 15:17:00 | [匿名:dali]
 C#3.0 中的擴展方法 (Extension Methods) 編輯
今天早上在MSDN站點看到這樣一篇文章:C#3.0LINQ的演變及其對C#設計的影響
2007-12-17 12:26:00 | [匿名:csdnexpert]
C#3.0介紹 編輯
以下資源僅供大家參考: 1、自動屬性,對象初始化器,和集合初始化器 2、新Orcas語言特性:擴展方法 3、新Orcas語言特性:Lambda表達式 4、新Orcas語言特性:查詢句法...
2007-11-27 18:19:00 | [匿名:曹振華]
C#3.0介紹 編輯
以下資源僅供大家參考: 1、自動屬性,對象初始化器,和集合初始化器 2、新Orcas語言特性:擴展方法 3、新Orcas語言特性:Lambda表達式 4、新Orcas語言特性:查詢句法...
2007-11-27 18:19:00 | [匿名:曹振華]
Visual Studio 2008 和 .NET 3.5 發佈了 編輯
轉自:http://blog.joycode.com/scottgu/archive/2007/11/20/111568.aspx
2007-11-27 17:53:00 | [匿名:曹振華]
Visual Studio 2008 和 .NET 3.5 發佈了 編輯
今天我們發佈了VisualStudio2008和.NET3.5。你可以使用下面的鏈接下載其最終版: 如果你是MSDN訂閱者,你可以在MSDN訂閱網站下載(注:其中...
2007-11-20 16:44:00 | [匿名:大口仔]
Visual Studio 2008 和 .NET 3.5 發佈了 編輯
轉自:http://blog.joycode.com/scottgu/archive/2007/11/20/111568.aspx
2007-11-20 15:19:00 | [匿名:Randy0528]
回覆: 新Orcas語言特性:擴展方法 編輯
美捷科技(北京)有限公司是一家致力於數字化期刊出版,期刊採編,[URL=http://www.meijiebj.com]期刊採編軟件[/URL]開發,以追求採編出版自由和文化繁榮爲己任的高科技企業!
2007-11-08 14:18:00 | [匿名:sfeas]
技巧/訣竅:用 .NET 3.5 創建 ToJSON() 擴展方法 (木野狐譯) 編輯
【原文地址】 Tip/Trick: Building a ToJSON() Extension Method using .NET 3.5 【原文發表日期】 Monday, October 01, 2007
2007-10-10 10:53:00 | [匿名:[email protected]]
C#3.0 中的擴展方法 (Extension Methods) (轉) 編輯
今天早上在MSDN站點看到這樣一篇文章:C#3.0LINQ的演變及其對C#設計的影響
2007-09-11 17:47:00 | [匿名:徐鋼]
C#3.0 中的擴展方法 (Extension Methods) 編輯
今天早上在MSDN站點看到這樣一篇文章:C#3.0LINQ的演變及其對C#設計的影響
2007-09-11 17:46:00 | [匿名:徐鋼]
VS 2008 和 .NET 3.5 Beta 2 發佈了(轉帖) 編輯
VS 2008 和 .NET 3.5 Beta 2 發佈了(轉帖)
2007-09-06 22:38:00 | [匿名:IMustDo]
C#3.0美文收集 編輯
今天在蟈蟈俊.net上看到一個關於.net3.0好文章收集的帖子,就順手轉了過來。 另外我又加了李建忠老師C#3.0銳利體驗系列課程的鏈接,以後如果發現好的 將會繼續更新。 大家如果有什麼好的文章...
2007-09-01 22:33:00 | [匿名:張榮華]
回覆: 新Orcas語言特性:擴展方法 編輯
值得已讀,對LINQ的查詢功能實在刮目想看!
2007-08-28 00:24:00 | [匿名:ricky52529]
新Orcas語言特性:查詢句法 編輯
新Orcas語言特性:查詢句法
2007-08-22 10:08:00 | [匿名:BoardPung]
關於 Orcas 信息收集 編輯
本節收集關於Orcas的信息,便於以後學習和交流。
2007-08-21 10:41:00 | [匿名:SmartSoft]
VS 2008 和 .NET 3.5 Beta 2 發佈了 編輯
VS2008和.NET3.5Beta2發佈了 【原文地址】VS2008and.NET3.5Beta2Released【原文發表日期】Thursday,July...
2007-08-17 13:52:00 | [匿名:ejiyuan]
VS 2008 和 .NET 3.5 Beta 2 發佈了 編輯
【原文地址】 VS 2008 and .NET 3.5 Beta 2 Released 【原文發表日期】 Thursday, July 26, 2007 2:11 PM 我非常高興地宣佈,VS 2008和
2007-07-30 12:17:00 | [匿名:[email protected]]
新Orcas語言特性:Lambda表達式。 編輯
隨VS 2005發佈的C#2.0引進了匿名方法的概念,允許在預期代理(delegate)值的地方用“行內(in-line)”代碼塊(code blocks)來做替代。 
2007-06-25 00:37:00 | [匿名:勤勤同學]
C#3.0 中的擴展方法 (Extension Methods) 編輯
今天早上在MSDN站點看到這樣一篇文章: C# 3.0 LINQ 的演變及其對 C# 設計的影響 。 從這篇文章我們就可以明顯的看到,C# 3.0 所新增的這些特性,可以認爲都是爲了LINQ 的發展,爲了LINQ更易用
2007-06-06 11:36:00 | [匿名:[email protected]]
C#3.0 中的擴展方法 (Extension Methods) 編輯
今天早上在MSDN站點看到這樣一篇文章: C# 3.0 LINQ 的演變及其對 C# 設計的影響
2007-06-06 11:28:00 | [匿名:ghj1976]
新Orcas語言特性:匿名類型 編輯
【原文地址】 New &quot;Orcas&quot; Language Feature: Anonymous Types 【原文發表日期】 Tuesday, May 15, 2007 7:02 AM
2007-05-21 10:26:00 | [匿名:[email protected]]
LINQ篇:查詢句法[轉] 編輯
2007-04-25 20:47:00 | [匿名:MonkRui]
[不蒐集不行]新Orcas語言特性:查詢句法 編輯
fromhttp://weblogs.asp.net/scottgufromhttp://blog.joycode.com/scottgu/archive/2007/04/24/101654.as...
2007-04-24 22:43:00 | [匿名:ColdDog]
新Orcas語言特性:Lambda表達式 編輯
什麼是Lambda表達式?Lambda表達式爲編寫匿名方法提供了更簡明的函數式的句法,但結果卻在編寫LINQ查詢表達式時變得極其有用,因爲它們提供了一個非常緊湊的而且類安全的方式來編寫可以當作參數來傳遞,在以後作運算的函數。
2007-04-10 13:38:00 | [匿名:shoutor]
新Orcas語言特性:擴展方法 編輯
什麼是擴展方法 (Extension Methods)?擴展方法允許開發人員往一個現有的CLR類型的公開契約(contract)中添加新的方法,而不用生成子類或者重新編譯原來的類型。擴展方法有助於把今天動態語言中流行的對duck typing的支持之靈活性,與強類型語言之性能和編譯時驗證融合起來。
2007-04-10 13:35:00 | [匿名:shoutor]
新Orcas語言特性:Lambda表達式 編輯
什麼是Lambda表達式?Lambda表達式爲編寫匿名方法提供了更簡明的函數式的句法,但結果卻在編寫LINQ查詢表達式時變得極其有用,因爲它們提供了一個非常緊湊的而且類安全的方式來編寫可以當作參數來傳遞,在以後作運算的函數。
2007-04-10 13:35:00 | [匿名:shoutor]
回覆: 新Orcas語言特性:擴展方法 編輯
看來 orcas的新功能還真不少,期待中
2007-04-07 21:12:00 | [匿名:cgdou]
回覆: 新Orcas語言特性:擴展方法 編輯
這篇文章我好幾天前就看了英文原版了。確實很值得仔細一讀。可以讓你感受到C# 3.0的強大。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章