C# 3.0中的分部方法

來源:互聯網
上載者:User

緣起兼序

  剛剛過去的這個周末對我來說非常之有意義。其一,周五搞來了一本《上帝擲骰子嗎?》,一本講量子理論的科普讀物,昏天黑地地從周五晚上一直看到周六夜裡,感觸良多此處不便多表,總之在精神分裂的邊緣轉了一圈。周日早早起床迎接我的一些朋友,來了個私人的.NET技術交流會,交流了CodePlex應用、Linq和資料庫的一些技術。

  而其中最讓人興奮的是,周六的時候Visual Studio 2008發布了Beta2版。有了Vista和VS2005的教訓,我曾發誓不碰Beta2之前版本的任何工具和技術。但不代表我不關注這些技術。所以VS2008 Beta2出來之後,我第一時間用QQ的下載工具down了一個下來,但安裝的時候竟然報告安裝檔案有錯誤,不得已只好到MSDN Subcribtion去用微軟自己的工具重新下載,直到周日夜裡,才終於下載完畢並安裝好。

  安裝完了之後,我也沒力氣玩了,直接睡覺。直到今天才終於能摸一摸。第一步,當然是去看What's New。

分部方法的文法

  在看C#語言的What's New時,突然發現新特性列表的最後,多出了一個“Partial Method Definitions ”,但並不像其他新特性一樣有超連結連結到其說明。上網搜尋了一下,關於部分型別的資訊非常少。尤其是中文資訊,只有CSDN的 周融 在其《C# 3.5 語言在 Visual Studio Orcas Beta 1 上的新增功能(二) 》一文的最後提到了這個分部方法,但沒有進一步說明。英文技術文章中,倒是有兩篇不錯的:http://blogs.msdn.com/wesdyer/archive/2007/05/23/in-case-you-haven-t-heard.aspx 和 http://community.bartdesmet.net/blogs/bart/archive/2007/07/28/c-3-0-partial-methods-what-why-and-how.aspx。

  又仔細看了一下MSDN Library for Visual Studio 2008 Beta 2,終於對這個語言特性有所瞭解,在這裡介紹一下,希望對大家有所協助。

  分部方法的定義和部分型別類似,只需在方法定義前添加partial關鍵字。但分部方法只能拆分成兩個部分——一部分是定義聲明(Definition Declaration),另一部分是實現聲明(Implement Declaration)。其中定義聲明看上去和抽象方法類似:

partial class CA
{
    // ...
    private void partial M();  // 定義聲明| 

  而實現聲明看上去和普通方法類似:

private void partial M()    // 實現聲明
{
    // 方法體
}

  在調用分部方法時,和調用其他方法一樣:

CA a = new CA();
a.M(); 

  只是,如果只有定義聲明而沒有編寫實現聲明,則編譯器不會發射(Emit)該方法和調用該方法的語句的中繼資料與IL代碼。換言之,如果沒有編寫實現聲明,則編譯得到的程式集中,CA類型裡並沒有M這個方法。

使用分部方法的注意事項

  分部方法的文法非常簡單,但有一些事項要注意。 

  • 如果沒有寫實現聲明,則不會發射方法調用代碼,也不會對參數進行求值。因此,對於下面的例子:

class CA
{
    partial void M(int i);

    static void Main()
    {
        CA a = new CA();
        int i = 0;
        a.M(i++);
    }
}

  分部方法M只有定義聲明,沒有實現聲明,因此也不會發射調用該方法的代碼:a.M(i++),因此也不會對i++進行求值。所以最終i的值依然是0。但如果為M編寫了實現聲明,則a.M(i++)的代碼會被編譯到最終的程式集中,同時參數也被求值,i的值將被變為1。 

  • 分部方法只能出現在部分類別中。
  • 分部方法必須是私人(private)的,並且傳回值類型必須是void。
  • 分部方法可以帶有參數,並且其參數可以帶有this、params和ref修飾符,但不能帶有out修飾符。
  • 分部方法不可以是虛擬(virtual)的。
  • 分部方法不可以是外部(extern)的。
  • 分部方法可以是靜態(static)的,也可以是不安全(unsafe)的。
  • 分部方法可以是泛型方法,泛型約束必須放置在定義聲明中,但也可以在事先聲明中重複說明。在定義聲明和實現聲明中,型別參數和型別參數的名字不一定必須一致。
  • 不能將分部方法封裝到一個委託中。

分部方法的應用情境

  分部方法和部分型別的初衷是類似的,一方面可以使得不同的開發人員能夠同時編寫一個類型的不同部分,另一方面可以分離自動產生的程式碼和使用者手寫的代碼。和部分型別一樣,分部方法也會在編譯初期被合并成一個方法定義。猜測:從微軟的角度來看,第二個“初衷”可能才是真正的初衷。

  由此,分部方法有如下幾個應用情境:(情境1 出自In Case You Haven't Heard這篇文章【http://blogs.msdn.com/wesdyer/archive/2007/05/23/in-case-you-haven-t-heard.aspx】),情境2 出自Visual Studio 2008的Linq to SQL技術,而情境3 則是Anders Liu自已臆想出來的。

情境1 輕量級事件處理

  有的時候,自動產生的程式碼需要事件這類語言構造來通知使用者對某些操作進行處理,但實際上用於編寫的代碼就位於自動產生的類型之中。此時,或者需要觸發一個事件,或者就需要產生一個virtual方法來讓使用者繼承。但無論是事件還是繼承,開銷都是比較大的,所以可以通過分部方法來實現輕量級的處理方式。如下面的類:(本例子引用自前述的In Case You Haven't Heard一文)

partial class Customer
{
    string name; 

    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            OnBeforeUpdateName();
            OnUpdateName();
            name = value;
            OnAfterUpdateName();
        }
    } 

    partial void OnBeforeUpdateName();
    partial void OnAfterUpdateName();
    partial void OnUpdateName();
}

  這裡定義了三個分部方法,其意義不言而喻。假設這是系統自動產生的程式碼,則我們只需在另外一個原始碼檔案中的partial class Customer中實現這幾個分部方法即可。 

情境2 自訂DataContext中的Insert、Update、Delete方法

  當使用Linq to SQL向項目中加入了實體類之後,還會建立一個XxxDataContext類,這個類繼承自DataContext類,並且是partial的。這個類封裝了具體的資料庫操作功能(實體類僅封裝資料庫中的資料),如對象的插入、更新和刪除等。

  下面我們來看一下這個自動產生的類定義:

[System.Data.Linq.Mapping.DatabaseAttribute(Name="AdventureWorks")]
public partial class AdventureWorksDataContext : System.Data.Linq.DataContext
{
  
    private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();
  
    #region Extensibility Method Definitions
    partial void OnCreated();
    partial void InsertAWBuildVersion(AWBuildVersion instance);
    partial void UpdateAWBuildVersion(AWBuildVersion instance);
    partial void DeleteAWBuildVersion(AWBuildVersion instance);
...... 

  這裡我們可以看到一系列的partial方法。其中第一個OnCreated實際上屬於情境1中描述的情況,是一個輕量級的事件,表示DataContext環境對象建立完畢。而其他partial方法則用於自訂DataContext的IUD操作。對於每一個表(實體類),這裡都會出現一組InsertXxx、UpdateXxx和DeleteXxx方法。如果我們希望自訂刪除行為(如希望將一個IsDelete欄位設定為true來表示已刪除),則可以在另一個檔案中擴充這個partial類,並為對應的Delete方法提供實現聲明。

情境3 新的調試資訊輸出方法

  這是Anders Liu臆想的情境,在分部方法的協助下,我們可以寫出這樣的代碼:

partial class CA
{
    partial void DebugPrint(string msg);
...
    void F()
    {
        ....
        DebugPrint("aaa");
    }

partial class CA
{
#if DEBUG
    partial void DebugPrint(string msg);
    {
        Debug.WriteLine(msg);
    }
#endif

  這樣做的好處在於,我們還是反過來說罷,如果不這樣做,必須在每次調用調試代碼時都加入#if判斷。而這樣可以將調試代碼都寫成方法,在一處用#if進行判斷。

  缺點在於,由於分部方法必須是私人的,所以必須針對每個類寫一套調試代碼。

小結 

  嗯,總而言之,Anders Liu在這篇文章裡說的是分部方法。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.