熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

C# 3.0中的分部方法

2022-06-13   來源: .NET編程 

  分部方法的語法

  在看C#語言的Whats New時突然發現新特性列表的最後多出了一個Partial Method Definitions 但並不像其他新特性一樣有超鏈接鏈接到其說明上網搜索了一下關於分部類型的信息非常少尤其是中文信息只有CSDN的 周融 在其《C# 語言在 Visual Studio Orcas Beta 上的新增功能(二) 》一文的最後提到了這個分部方法但沒有進一步說明英文技術文章中倒是有兩篇不錯的heardaspx 和 partial methodswhatwhyandhowaspx

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

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

  partial class CA

  {

  // ……

  private void partial M() // 定義聲明|

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

  private void partial M() // 實現聲明

  {

  // 方法體

  }

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

  CA a = new CA()

  aM()

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

  使用分部方法的注意事項

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

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

  

  class CA
{
partial void M(int i);

static void Main()
{
CA a = new CA();
int i = ;
aM(i++);
}
}

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

  分部方法只能出現在分部類中

  分部方法必須是私有(private)的並且返回值類型必須是void

  分部方法可以帶有參數並且其參數可以帶有thisparams和ref修飾符但不能帶有out修飾符

  分部方法不可以是虛擬(virtual)的

  分部方法不可以是外部(extern)的

  分部方法可以是靜態(static)的也可以是不安全(unsafe)的

  分部方法可以是泛型方法泛型約束必須放置在定義聲明中但也可以在事先聲明中重復說明在定義聲明和實現聲明中類型參數和類型參數的名字不一定必須一致

  不能將分部方法封裝到一個委托中

  分部方法的應用場景

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

  由此分部方法有如下幾個應用場景(場景 出自In Case You Havent Heard這篇文章「caseyou haventheardaspx」)場景 出自Visual Studio 的Linq to SQL技術而場景 則是Anders Liu自已臆想出來的

  場景 輕量級事件處理

  有的時候自動生成的代碼需要事件這類語言構造來通知用戶對某些操作進行處理但實際上用於編寫的代碼就位於自動生成的類型之中此時或者需要觸發一個事件或者就需要生成一個virtual方法來讓用戶繼承但無論是事件還是繼承開銷都是比較大的所以可以通過分部方法來實現輕量級的處理方式如下面的類(本例子引用自前述的In Case You Havent 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中實現這幾個分部方法即可

  場景 自定義DataContext中的InsertUpdateDelete方法

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

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

  

  [SystemDataLinqMappingDatabaseAttribute(Name=AdventureWorks)]
public partial class AdventureWorksDataContext : SystemDataLinqDataContext
{

private static SystemDataLinqMappingMappingSource 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實際上屬於場景中描述的情況是一個輕量級的事件表示 DataContext環境對象創建完畢而其他partial方法則用於自定義DataContext的IUD操作對於每一個表(實體類)這裡都會出現一組InsertXxxUpdateXxx和DeleteXxx方法如果我們希望自定義刪除行為(如希望將一個IsDelete字段設置為 true來表示已刪除)則可以在另一個文件中擴展這個partial類並為對應的Delete方法提供實現聲明

  場景 新的調試信息輸出方法

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

  

  partial class CA
{
partial void DebugPrint(string msg);

void F()
{

DebugPrint(aaa);
}
}

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

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

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

  小結

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


From:http://tw.wingwit.com/Article/program/net/201311/13680.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.