委託(Delegate)

來源:互聯網
上載者:User
C# 中的委託類似於 C 或 C++ 中的函數指標。使用委託使程式員可以將方法引用封裝在委派物件內。然後可以將該委派物件傳遞給可調用所引用方法的代碼,而不必在編譯時間知道將調用哪個方法。與 C 或 C++ 中的函數指標不同,委託是物件導向、型別安全的,並且是安全的。

委託聲明定義一種類型,它用一組特定的參數以及傳回型別封裝方法。對於靜態方法,委派物件封裝要調用的方法。對於執行個體方法,委派物件同時封裝一個執行個體和該執行個體上的一個方法。如果您有一個委派物件和一組適當的參數,則可以用這些參數調用該委託。

委託的一個有趣且有用的屬性是,它不知道或不關心自己引用的對象的類。任何對象都可以;只是方法的參數類型和傳回型別必須與委託的參數類型和傳回型別相匹配。這使得委託完全適合“匿名”調用。

此教程包括兩個樣本:

樣本 1 展示如何聲明、執行個體化和調用委託。

樣本 2 展示如何組合兩個委託。

此外,還討論以下主題:

委託和事件

委託與介面

樣本 1

下面的樣本闡釋聲明、執行個體化和使用委託。BookDB 類封裝一個書店資料庫,它維護一個書籍資料庫。它公開 ProcessPaperbackBooks 方法,該方法在資料庫中尋找所有平裝書,並為每本書調用一個委託。所使用的 delegate 類型稱為 ProcessBookDelegate。Test 類使用該類輸出平裝書的書名和平均價格。

委託的使用促進了書店資料庫和客戶代碼之間功能的良好分隔。客戶代碼不知道書籍的儲存方式和書店代碼尋找平裝書的方式。書店代碼也不知道找到平裝書後將對平裝書進行什麼處理。

// bookstore.cs

using System;



// A set of classes for handling a bookstore:

namespace Bookstore

{

using System.Collections;

// Describes a book in the book list:

public struct Book

{

public string Title; // Title of the book.

public string Author; // Author of the book.

public decimal Price; // Price of the book.

public bool Paperback; // Is it paperback?

public Book(string title, string author, decimal price, bool paperBack)

{

Title = title;

Author = author;

Price = price;

Paperback = paperBack;

}

}

// Declare a delegate type for processing a book:

public delegate void ProcessBookDelegate(Book book);

// Maintains a book database.

public class BookDB

{

// List of all books in the database:

ArrayList list = new ArrayList();

// Add a book to the database:

public void AddBook(string title, string author, decimal price, bool paperBack)

{

list.Add(new Book(title, author, price, paperBack));

}

// Call a passed-in delegate on each paperback book to process it:

public void ProcessPaperbackBooks(ProcessBookDelegate processBook)

{

foreach (Book b in list)

{

if (b.Paperback)

// Calling the delegate:

processBook(b);

}

}

}

}

// Using the Bookstore classes:

namespace BookTestClient

{

using Bookstore;

// Class to total and average prices of books:

class PriceTotaller

{

int countBooks = 0;

decimal priceBooks = 0.0m;

internal void AddBookToTotal(Book book)

{

countBooks += 1;

priceBooks += book.Price;

}

internal decimal AveragePrice()

{

return priceBooks / countBooks;

}

}

// Class to test the book database:

class Test

{

// Print the title of the book.

static void PrintTitle(Book b)

{

Console.WriteLine(" {0}", b.Title);

}

// Execution starts here.

static void Main()

{

BookDB bookDB = new BookDB();

// Initialize the database with some books:

AddBooks(bookDB);

// Print all the titles of paperbacks:

Console.WriteLine("Paperback Book Titles:");

// Create a new delegate object associated with the static

// method Test.PrintTitle:

bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle));

// Get the average price of a paperback by using

// a PriceTotaller object:

PriceTotaller totaller = new PriceTotaller();

// Create a new delegate object associated with the nonstatic

// method AddBookToTotal on the object totaller:

bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(totaller.AddBookToTotal));

Console.WriteLine("Average Paperback Book Price: ${0:#.##}",

totaller.AveragePrice());

}

// Initialize the book database with some test books:

static void AddBooks(BookDB bookDB)

{

bookDB.AddBook("The C Programming Language",

"Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true);

bookDB.AddBook("The Unicode Standard 2.0",

"The Unicode Consortium", 39.95m, true);

bookDB.AddBook("The MS-DOS Encyclopedia",

"Ray Duncan", 129.95m, false);

bookDB.AddBook("Dogbert's Clues for the Clueless",

"Scott Adams", 12.00m, true);

}

}

}

輸出

Paperback Book Titles:

The C Programming Language

The Unicode Standard 2.0

Dogbert's Clues for the Clueless

Average Paperback Book Price: $23.97

代碼討論

聲明委託 以下語句:

public delegate void ProcessBookDelegate(Book book);

聲明一個新的委託類型。每個委託類型都描述參數的數目和類型,以及它可以封裝的方法的傳回值類型。每當需要一組新的參數類型或新的傳回值類型時,都必須聲明一個新的委託類型。

執行個體化委託 聲明了委託類型後,必須建立委派物件並使之與特定方法關聯。與所有其他對象類似,新的委派物件用 new 運算式建立。但建立委託時,傳遞給 new 運算式的參數很特殊:它的編寫類似於方法調用,但沒有方法的參數。

下列語句:

bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle));

建立與靜態方法 Test.PrintTitle 關聯的新的委派物件。下列語句:

bookDB.ProcessPaperbackBooks(new

ProcessBookDelegate(totaller.AddBookToTotal));

建立與對象 totaller 上的非靜態方法 AddBookToTotal 關聯的新的委派物件。在兩個例子中,新的委派物件都立即傳遞給 ProcessPaperbackBooks 方法。

請注意一旦建立了委託,它所關聯到的方法便永不改變:委派物件不可改變。

調用委託 建立委派物件後,通常將委派物件傳遞給將調用該委託的其他代碼。通過委派物件的名稱(後面跟著要傳遞給委託的參數,括在括弧內)調用委派物件。下面是委託調用的樣本:

processBook(b);

樣本 2

本樣本示範組合委託。委派物件的一個有用屬性是,它們可以“+”運算子來組合。組合的委託依次調用組成它的兩個委託。只可組合相同類型的委託,並且委託類型必須具有 void 傳回值。“-”運算子可用來從組合的委託移除組件委託。

// compose.cs

using System;

delegate void MyDelegate(string s);

class MyClass

{

public static void Hello(string s)

{

Console.WriteLine(" Hello, {0}!", s);

}

public static void Goodbye(string s)

{

Console.WriteLine(" Goodbye, {0}!", s);

}

public static void Main()

{

MyDelegate a, b, c, d;

// Create the delegate object a that references

// the method Hello:

a = new MyDelegate(Hello);

// Create the delegate object b that references

// the method Goodbye:

b = new MyDelegate(Goodbye);

// The two delegates, a and b, are composed to form c,

// which calls both methods in order:

c = a + b;

// Remove a from the composed delegate, leaving d,

// which calls only the method Goodbye:

d = c - a;

Console.WriteLine("Invoking delegate a:");

a("A");

Console.WriteLine("Invoking delegate b:");

b("B");

Console.WriteLine("Invoking delegate c:");

c("C");

Console.WriteLine("Invoking delegate d:");

d("D");

}

}

輸出

Invoking delegate a:

Hello, A!

Invoking delegate b:

Goodbye, B!

Invoking delegate c:

Hello, C!

Goodbye, C!

Invoking delegate d:

Goodbye, D!

委託和事件

委託非常適合於用作事件(從一個組件就該組件中的更改通知“接聽程式”)。

委託與介面

委託和介面的類似之處是,它們都允許分隔規範和實現。多個獨立的作者可以產生與一個介面規範相容的多個實現。類似地,委託指定方法的簽名,多個作者可以編寫與委託規範相容的多個方法。何時應使用介面,而何時應使用委託呢?

委託在以下情況下很有用:

調用單個方法。

一個類可能希望有方法規範的多個實現。

希望允許使用靜態方法實現規範。

希望類似事件的設計模式。

調用方不需要知道或獲得在其上定義方法的對象。

實現的提供者希望只對少數選擇組件“分發”規範實現。

需要方便的組合。

介面在以下情況下很有用:

規範定義將調用的一組相關方法。

類通常只實現規範一次。

介面的調用方希望轉換為介面類型或從介面類型轉換,以獲得其他介面或類。

相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

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

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