程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#3.0的分部方法

C#3.0的分部方法

編輯:關於C#

C#分部方法的語法

在看C#語言的What's New時,突然發現新特性列表的最後,多出了一個“Partial Method Definitions”,但並不像其他新特性一樣有超鏈接鏈接到其說明。上網搜索了一下,關於分部類型的信息非常少。尤其是中文信息,英文技術文章中,倒是有兩篇不錯的: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在這篇文章裡說的是分部方法。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved