委托
这篇教程论述了委托类型,它显示了如何委托映射到静态方法和实例方法,以及如何将他们相结合(多播)。
延伸阅读
教程
C#中的委托类似于C或C++中的函数指针,使用委托允许开发者将一个函数引用封装进一个委托对象,然后,委托对象可以作为参数传到需要调用这个函数的代码块中,编译时不需要知道哪个函数会被调用。和C或C++的区别在于,委托是面向对象、类型安全和过程安全的。
委托声明定义了一种将函数的参数和返回值封装的类型。对于静态方法,委托将方法封装以便于被调用。对于实例方法,委托将实例和方法一起封装进这个委托实例。如果你知道一个委托的实例和适当的参数,你就可以通过参数调用这个委托。
委托有一个既有趣有比较有用的特性是,他不知道或者不关心引用对象的类型,任何对象都会执行一样的操作,重要的是函数的参数类型和返回值是否和委托匹配。这让委托非常适合“匿名”调用。
注:委托在调用处而不是声明处的安全许可下运行。
本教程有两个例子:
除此之外,还讨论了下面两个话题:
实例1
下面的例子阐明声明、实例化和如何使用一个委托。BookDB类封装了书店数据库中的书籍数据,它暴露了一个方法ProcessPaperbakcBooks,找到所有书籍数据然后为每个数据调用一个委托,委托的名字是ProcessBookDelegate。Test类使用这个类打印每本平装书的书名和计算平均价格。
委托的作用就是提升书店数据库和客户端代码的功能的良好分隔(耦合度)。客户端代码不知道书籍信息是如何存储也不知道bookstore中的代码是如何找到所有平装书的,bookesotre也不知道当他找到所有平装书后会执行什么流程。
--------------------------------------------------------------------------------------------------------------------
// 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);
声明一个新的委托类型。任何委托类型都是描述参数的数量和类型,以及他封装的方法的返回值类型。每当需要一组新的参数类型或返
回值类型,必须声明一个新的委托类型。
bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle));
创建一个新的委托对象,指定静态方法Test.PrintTitle.
bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(totaller.AddBookToTotal));
创建一个新的委托对象指定一个totaller中的非静态的方法AddBookToTotal。这两种情况下,委托对象都会立即传送至ProcessPaperbakcBooks方法。
注意,一旦创建了一个委托,它所指定的函数标签就不能改变-委托对象是不可变的。
processBook(b);
委托既能同步调用就想本例中一样,也能异步调用,异步调用使用 BeginInvoke 和 EndInvoke 方法。
原文地址:http://www.cnblogs.com/fly-100/p/3753771.html