委托解释
?
經(jīng)常許多人問的,.Net中的委托以及事件處理。我拿簡單的例子說明一下,是現(xiàn)實(shí)中的例子:
比如說一個(gè)公司(場(chǎng)景),你是老板,手下有兩個(gè)員工,小張和小王。
你命令小王,如果小張玩游戲,則小王扣去小張500元錢。
這就是現(xiàn)實(shí)中的委托。
實(shí)際上,在寫程序中,程序員就是老板,小張和小王就是兩個(gè)對(duì)象。小張玩游戲是一個(gè)方法,小張還有一個(gè)游戲事件,他玩游戲激發(fā)這個(gè)事件。而小王就是事件處理對(duì)象,他負(fù)責(zé)把小張的錢扣除500。
所以,委托有如下幾個(gè)要素:
1 激發(fā)事件的對(duì)象--就是小張
2 處理對(duì)象事件的對(duì)象--就是小王
3 定義委托,就是你讓小王監(jiān)視小張。
如果這三個(gè)要素都滿足的話,則你就寫出了一個(gè)完整事件的處理。
下面有個(gè)例子:在vs.net2003 C#控制臺(tái)應(yīng)用程序編輯運(yùn)行成功:
using System;
namespace CSharpConsole
{
??? public class 場(chǎng)景
??? {
??????? [STAThread]
??????? public static void Main(string[] args)
??????? {
??? Console.WriteLine("場(chǎng)景開始了.");
??? // 生成小王
??? 小王 w = new 小王();
??? // 生成小賬
??? 小張 z = new 小張();
??? // 指定監(jiān)視
??? z.PlayGame += new PlayGameHandler(w.扣錢);
???????????
??? // 開始玩游戲
??? z.玩游戲();
??? Console.WriteLine("場(chǎng)景結(jié)束");
??? Console.ReadLine();
???????? }
??? }
??? // 負(fù)責(zé)扣錢的人
??? public class 小王
??? {
??? public 小王()
??? {
????????????? Console.WriteLine("生成小王");
??? }
??? public void 扣錢(object sender,EventArgs e)
??? {
??????? Console.WriteLine("小王:好小子,上班時(shí)間膽敢玩游戲");
??????? Console.WriteLine("小王:看看你小子有多少錢");
??????? 小張 f = (小張)sender;
??????? Console.WriteLine("小張的錢: " + f.錢.ToString());
??????? Console.WriteLine("開始扣錢");
??????? System.Threading.Thread.Sleep(500);
??????? f.錢 = f.錢 - 500;
??????? Console.WriteLine("扣完了.現(xiàn)在小張還剩下:" + f.錢.ToString());
??? }
??? }
??? // 如果玩游戲,則引發(fā)事件
??? public class 小張
??? {
??? // 先定義一個(gè)事件,這個(gè)事件表示“小張”在玩游戲。
???????? public event PlayGameHandler PlayGame;
??? // 保存小張錢的變量
??? private int m_Money;
??? public 小張()
??? {
??????? Console.WriteLine("生成小張.");
??????? m_Money = 1000; // 構(gòu)造函數(shù),初始化小張的錢。
??? }
??? public int 錢 // 此屬性可以操作小張的錢。
??? {
??????? get
??????? {
??????????? return m_Money;
??????? }
??????? set
??????? {
??????????? m_Money = value;
??????? }
??? }
??? public void 玩游戲()
??? {
??????? Console.WriteLine("小張開始玩游戲了..");
??????? Console.WriteLine("小張:CS好玩,哈哈哈!我玩..");
??????? System.Threading.Thread.Sleep(500);
??????? System.EventArgs e = new EventArgs();
??????? OnPlayGame(e);
??? }
??? protected virtual void OnPlayGame(EventArgs e)
??? {
??????? if(PlayGame != null)
??????? {
??????????? PlayGame(this,e);
??????? }
??? }
??? }
??? // 定義委托處理程序
??? public delegate void PlayGameHandler(object sender,System.EventArgs e);
}
----------------------------------------------------------------------------------------------------------------------------------------
2C# 中的委托類似于 C 或 C++ 中的函數(shù)指針。使用委托使程序員可以將方法引用封裝在委托對(duì)象內(nèi)。然后可以將該委托對(duì)象傳遞給可調(diào)用所引用方法的代碼,而不必在編譯時(shí)知道將調(diào)用哪個(gè)方法。與 C 或 C++ 中的函數(shù)指針不同,委托是面向?qū)ο蟆㈩愋桶踩?#xff0c;并且是安全的。
委托聲明定義一種類型,它用一組特定的參數(shù)以及返回類型封裝方法。對(duì)于靜態(tài)方法,委托對(duì)象封裝要調(diào)用的方法。對(duì)于實(shí)例方法,委托對(duì)象同時(shí)封裝一個(gè)實(shí)例和該實(shí)例上的一個(gè)方法。如果您有一個(gè)委托對(duì)象和一組適當(dāng)?shù)膮?shù),則可以用這些參數(shù)調(diào)用該委托。
委托的一個(gè)有趣且有用的屬性是,它不知道或不關(guān)心自己引用的對(duì)象的類。任何對(duì)象都可以;只是方法的參數(shù)類型和返回類型必須與委托的參數(shù)類型和返回類型相匹配。這使得委托完全適合“匿名”調(diào)用。
此教程包括兩個(gè)示例:
示例 1 展示如何聲明、實(shí)例化和調(diào)用委托。
示例 2 展示如何組合兩個(gè)委托。
此外,還討論以下主題:
委托和事件
委托與接口
示例 1
下面的示例闡釋聲明、實(shí)例化和使用委托。BookDB 類封裝一個(gè)書店數(shù)據(jù)庫,它維護(hù)一個(gè)書籍?dāng)?shù)據(jù)庫。它公開 ProcessPaperbackBooks 方法,該方法在數(shù)據(jù)庫中查找所有平裝書,并為每本書調(diào)用一個(gè)委托。所使用的 delegate 類型稱為 ProcessBookDelegate。Test 類使用該類輸出平裝書的書名和平均價(jià)格。
委托的使用促進(jìn)了書店數(shù)據(jù)庫和客戶代碼之間功能的良好分隔。客戶代碼不知道書籍的存儲(chǔ)方式和書店代碼查找平裝書的方式。書店代碼也不知道找到平裝書后將對(duì)平裝書進(jìn)行什么處理。
// 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);
聲明一個(gè)新的委托類型。每個(gè)委托類型都描述參數(shù)的數(shù)目和類型,以及它可以封裝的方法的返回值類型。每當(dāng)需要一組新的參數(shù)類型或新的返回值類型時(shí),都必須聲明一個(gè)新的委托類型。
實(shí)例化委托 聲明了委托類型后,必須創(chuàng)建委托對(duì)象并使之與特定方法關(guān)聯(lián)。與所有其他對(duì)象類似,新的委托對(duì)象用 new 表達(dá)式創(chuàng)建。但創(chuàng)建委托時(shí),傳遞給 new 表達(dá)式的參數(shù)很特殊:它的編寫類似于方法調(diào)用,但沒有方法的參數(shù)。
下列語句:
bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle));
創(chuàng)建與靜態(tài)方法 Test.PrintTitle 關(guān)聯(lián)的新的委托對(duì)象。下列語句:
bookDB.ProcessPaperbackBooks(new
?? ProcessBookDelegate(totaller.AddBookToTotal));
創(chuàng)建與對(duì)象 totaller 上的非靜態(tài)方法 AddBookToTotal 關(guān)聯(lián)的新的委托對(duì)象。在兩個(gè)例子中,新的委托對(duì)象都立即傳遞給 ProcessPaperbackBooks 方法。
請(qǐng)注意一旦創(chuàng)建了委托,它所關(guān)聯(lián)到的方法便永不改變:委托對(duì)象不可改變。
調(diào)用委托 創(chuàng)建委托對(duì)象后,通常將委托對(duì)象傳遞給將調(diào)用該委托的其他代碼。通過委托對(duì)象的名稱(后面跟著要傳遞給委托的參數(shù),括在括號(hào)內(nèi))調(diào)用委托對(duì)象。下面是委托調(diào)用的示例:
processBook(b);
示例 2
本示例演示組合委托。委托對(duì)象的一個(gè)有用屬性是,它們可以“+”運(yùn)算符來組合。組合的委托依次調(diào)用組成它的兩個(gè)委托。只可組合相同類型的委托,并且委托類型必須具有 void 返回值。“-”運(yùn)算符可用來從組合的委托移除組件委托。
// 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!
委托和事件
委托非常適合于用作事件(從一個(gè)組件就該組件中的更改通知“偵聽器”)。
委托與接口
轉(zhuǎn)載于:https://www.cnblogs.com/hanyihua99/archive/2007/10/10/919707.html
總結(jié)
- 上一篇: 一部IT电影,《反托拉斯行动》,主角加里
- 下一篇: 也论PageController/Fro