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