[转载]C# delegate – 《孙金棚的程序人生》 – 博客园.
.Net 中的委托类似于 C 或 C++ 中的函数指针。使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方 法。与 C 或 C++ 中的函数指针不同,委托是面向对象、类型安全的,并且是安全的。
委托声明定义一种类型,它用一组特定的参数以及返回类型封装方法。对于静态方法,委托对象封装要调用的方法。对于实例方法,委托对象同时封装一 个实例和该实例上的一个方法。如果您有一个委托对象和一组适当的参数,则可以用这些参数调用该委托。委托的一个有趣且有用的属性是,它不知道或不关心自己 引用的对象的类。任何对象都可以;只是方法的参数类型和返回类型必须与委托的参数类型和返回类型相匹配。这使得委托完全适合“匿名”调用。
在任何地方都可以使用Delegates
在这一点上,也许你只知道有这样一回事,但却没有察觉它在你的程序中的应用。虽然你没 有建立自己的delegates,但如果经常使用事件时你会使用到它们。一个极好的例子就是ASP.NET中使用的事件。在后台使用的Delegates 围绕着事件工作。事件使用一个标记,你也可以在一个线程结构中找到delegates。
Delegate 和 interface
你必须注意的另一个点是一个delegate和一个接口之间的相似性,因为它们都将规范和执行分离开来。它们允许开发人员建立与规范相符合的执行。除此之外,方法标记必须是被指定和相兼容。
所以,你什么时候使用接口?以及你什么时候使用delegates?微软提供了以下的指导思想。
Delegates:
调用一个单一方法。 一个类要进行方法规范(method specification)的多种执行。 使用一个静态方法来执行规范。 想获得类似事件设计的模式。 调用者没有必要知道或获得方法定义的对象。 执行的提供者想将规范的执行“分发”成一些选择性的部分。
interface:
规范指定一套即将被调用的方法。 特别的,一个类只执行规范一次。 接口的调用者想通过接口类型以获得其它接口或类。
下面我们用示例来理解一下吧!…………………O(∩_∩)O
示例1
BookDB是一个书籍数据库、他公开了ProcessPaperbackBooks
方法、并且每本平装书都调用一个委托ProcessBookDelegate、从而得到书籍标题和平均价格
Code:
using System; namespace Bookstore { using System.Collections; public struct Book { public string Title; //标题 public string Author; // 作者 public decimal Price; // 价格 public bool Paperback; // 是否是平装书籍 public Book(string title, string author, decimal price, bool paperBack) { Title = title; Author = author; Price = price; Paperback = paperBack; } } //声明委托 参数是book public delegate void ProcessBookDelegate(Book book); // 模拟书籍数据库 public class BookDB { ArrayList list = new ArrayList(); //添加 public void AddBook(string title, string author, decimal price, bool paperBack) { list.Add(new Book(title, author, price, paperBack)); } // 处理平装书籍 public void ProcessPaperbackBooks(ProcessBookDelegate processBook) { foreach (Book b in list) { if (b.Paperback)//过滤平装书籍 processBook(b); } } } } //书籍平均价格 namespace BookTestClient { using Bookstore; 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 Test { //打印评价书籍标题 static void PrintTitle(Book b) { Console.WriteLine(" {0}", b.Title); } static void Main() { Console.WriteLine("创建书籍数据库"); BookDB bookDB = new BookDB(); AddBooks(bookDB); Console.WriteLine("增加书籍完毕"); Console.WriteLine("所有平装书名"); bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle)); PriceTotaller totaller = new PriceTotaller(); bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(totaller.AddBookToTotal)); Console.WriteLine("评价书籍平均价格是: ${0:#.##}", totaller.AveragePrice()); } static void AddBooks(BookDB bookDB) { bookDB.AddBook("C# 设计模式","X.Y", 19.95m, true); bookDB.AddBook("人月神话 ","X.Y", 39.95m, true); bookDB.AddBook("大话设计模式", "X.Y", 129.95m, false); bookDB.AddBook("精通C#", "X.Y", 12.00m, true); } } }
效果图
示例2
委托是可以用”+”和”-“来添加和移除的、但是要满足两个条件。条件一:必须是相同类型的委托、条件二:必须都是void返回值
Code:
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; a = new MyDelegate(Hello); b = new MyDelegate(Goodbye); c = a + b; d = c - a; Console.WriteLine("调用 delegate a:"); a("A"); Console.WriteLine("调用 delegate b:"); b("B"); Console.WriteLine("调用 delegate c:"); c("C"); Console.WriteLine("调用 delegate d:"); d("D"); } }
效果图