程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 程序員參考--委托教學文章

C# 程序員參考--委托教學文章

編輯:C#入門知識

本教程演示委托類型。它說明如何將委托映射到靜態方法和實例方法,以及如何組合委托(多路廣播)。

教程

C# 中的委托類似於 C 或 C++ 中的函數指針。使用委托使程序員可以將方法引用封裝在委托對象內。然後可以將該委托對象傳遞給可調用所引用方法的代碼,而不必在編譯時知道將調用哪個方法。與 C 或 C++ 中的函數指針不同,委托是面向對象、類型安全的,並且是安全的。

委托聲明定義一種類型,它用一組特定的參數以及返回類型封裝方法。對於靜態方法,委托對象封裝要調用的方法。對於實例方法,委托對象同時封裝一個實例和該實例上的一個方法。如果您有一個委托對象和一組適當的參數,則可以用這些參數調用該委托。

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

注意   委托是在調用方的安全權限下運行而不是聲明方的權限下運行。

此教程包括兩個示例:

  • 示例 1 展示如何聲明、實例化和調用委托。
  • 示例 2 展示如何組合兩個委托。

此外,還討論以下主題:

  • 委托和事件
  • 委托與接口

示例 1

下面的示例闡釋聲明、實例化和使用委托。BookDB 類封裝一個書店數據庫,它維護一個書籍數據庫。它公開 ProcessPaperbackBooks 方法,該方法在數據庫中查找所有平裝書,並為每本書調用一個委托。所使用的 delegate 類型稱為 ProcessBookDelegateTest 類使用該類輸出平裝書的書名和平均價格。

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

// 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.WriteLin

[1] [2] [3] 下一頁  

e("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);

    在此示例中,可以通過使用 BeginInvoke 和 EndInvoke 方法同步或異步調用委托。

示例 2

本示例演示組合委托。委托對象的一個有用屬性是,它們可以“+”運算符來組合。組合的委托可調用組成它的那兩個委托。只有相同類型的委托才可以組合。

-”運算符可用來從組合的委托移除組件委托。

// 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, a

上一頁  [1] [2] [3] 下一頁  

re composed to form c: 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!

委托和事件

委托非常適合於用作事件(從一個組件就該組件中的更改通知“偵聽器”)。有關將委托用於事件的更多信息,請參見事件教程。

委托與接口

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

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

  • 調用單個方法。
  • 一個類可能希望有方法規范的多個實現。
  • 希望允許使用靜態方法實現規范。
  • 希望類似事件的設計模式(有關更多信息,請參見事件教程)。
  • 調用方不需要知道或獲得在其上定義方法的對象。
  • 實現的提供程序希望只對少數選擇組件“分發”規范實現。
  • 需要方便的組合。

接口在以下情況下很有用:

  • 規范定義將調用的一組相關方法。
  • 類通常只實現規范一次。
  • 接口的調用方希望轉換為接口類型或從接口類型轉換,以獲得其他接口或類。


 

上一頁  [1] [2] [3] 

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