C#拾遗系列(1):委托
2008-06-11 14:43 敏捷的水 阅读(777) 评论(2) 编辑 收藏 举报一、委托概述
委托具有以下特点:
-
委托类似于 C++ 函数指针,但它们是类型安全的。
-
委托允许将方法作为参数进行传递。
-
委托可用于定义回调方法。
-
委托可以链接在一起;例如,可以对一个事件调用多个方法。
-
方法不必与委托签名完全匹配。(委托中的协变和逆变)
-
C# 2.0 版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。C# 3.0 引入了 Lambda 表达式,利用它们可以更简练地编写内联代码块。匿名方法和 Lambda 表达式(在某些上下文中)都可编译为委托类型。这些功能统称为匿名函数
二、委托申明和使用示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//Description: 委托三种声明方式.net1.0到.net3.0
namespace NetTest
{
public class TestDelegateNet1To3
{
#region 不带返回值的委托
delegate void TestDelegate(string s);
public void TestAllDelegate()
{
//.net 1.0
TestDelegate en = new TestDelegate(M);
en("jack");
TestDelegate china = China;
china("wangdeshui");
//.net 2.0
TestDelegate delegateNet2 = delegate(string s) { Console.Out.WriteLine(s + ":这是一个2.0的方式"); };
delegateNet2("2.0 delegate declare");
//.net 3.0
TestDelegate delegateNet3 = (string s) => { Console.Out.WriteLine(s + ":这是3.0的方式"); };
delegateNet3("3.0 delegate declare");
TestReturn();
Func<int, bool> d = (n) => { return n > 10 ? true : false; };
Console.Out.WriteLine("func<int, bool>:" + d(20));
}
void M(string s)
{
Console.Out.WriteLine(s + ":Good Morning");
}
void China(string s)
{
Console.Out.WriteLine(s + ":早上好");
}
#endregion
#region 带返回值的委托测试
delegate bool TestDelegateReturn(int i);
void TestReturn()
{
TestDelegateReturn Net10 = new TestDelegateReturn(IsBig);
bool i = Net10(11);
Console.Out.WriteLine("Net10:" + i);
TestDelegateReturn Net20 = delegate(int j)
{
return (j > 10 ? true : false);
};
bool test20 = Net20(5);
Console.Out.WriteLine("Net20:" + test20);
TestDelegateReturn Net30 = (int k) => { return (k > 10 ? true : false); };
bool test30 = Net30(50);
Console.Out.WriteLine("Net30:" + test30);
}
bool IsBig(int i)
{
return i > 10 ? true : false;
}
#endregion
}
}
三、多播委托
调用委托时,它可以调用多个方法。这称为多路广播。若要向委托的方法列表(调用列表)中添加额外的方法,只需使用加法运算符或加法赋值运算符(“+”或“+=”)添加两个委托。
注意:
作为委托参数传递的方法必须与委托声明具有相同的签名。
委托实例可以封装静态或实例方法。
尽管委托可以使用 out 参数,但建议您不要将其用于多路广播事件委托,因为您无法知道哪个委托将被调用。多播委托传递值类型时,对参数的修改不会传到下一个
多播委托传递引用类型时,对引用参数的修改会传到下一个示例:
public class TestMultiCastDelegate
{
public delegate void Del(string message);
delegate void DelRef(Person p);
void MethodA(string s)
{
Console.Out.WriteLine("Method A:"+s);
}
void MethodB(string s)
{
s = "good";
Console.Out.WriteLine("Method B:" + s);
}
void MethodC(string s)
{
Console.Out.WriteLine("Method C:" + s);
}
/*
多播委托传递值类型时,对参数的修改不会传到下一个
多播委托传递引用类型时,对引用参数的修改会传到下一个
*
* */
public void Test()
{
//多播委托
Del d1 = MethodA;
Del d2 = MethodB;
Del d3=MethodC;
Del AllDelegateMethod = d1 + d2;
AllDelegateMethod += d3;
AllDelegateMethod("Jack");
/*
output:
ConsoleA: Jack
ConsoleB: Jack
ConsoleC:Jack
*/
Console.Out.WriteLine("---------------------");
AllDelegateMethod -= d3;
AllDelegateMethod("wangds");
//测试引用类型
DelRef dref1 = MethodRefA;
DelRef dref2 = MethodRefB;
DelRef Alldref = dref1 + dref2;
Person p = new Person { Address = "USA", Name = "America" };
Alldref(p);
}
//内嵌类
class Person
{
public string Name { get; set; }
public string Address { get; set; }
}
void MethodRefA(Person p)
{
Console.Out.WriteLine(p.Name + "," + p.Address);
Console.Out.WriteLine("----------MethodRefA---------");
p.Name = "Jack";
p.Address = "China";
Console.Out.WriteLine(p.Name + "," + p.Address);
Console.Out.WriteLine("----------MethodRefA---------");
}
void MethodRefB(Person p)
{
Console.Out.WriteLine("--------MethodRefB----------");
Console.Out.WriteLine(p.Name + "," + p.Address);
Console.Out.WriteLine("--------MethodRefB----------");
}
}
四、委托中的协变和逆变
委托中的协变: 就是允许方法的返回类型是委托的返回类型的子类
委托中的逆变,方法的参数是委托的参数的基类
示例:
#region 委托中的协变: 就是允许方法的返回类型是委托的返回类型的子类
class Mammals
{
}
class Dogs : Mammals
{
}
class XieBianDelegate
{
// Define the delegate.
public delegate Mammals HandlerMethod();
public Mammals FirstHandler()
{
return null;
}
public Dogs SecondHandler()
{
return null;
}
void Test()
{
HandlerMethod handler1 = FirstHandler;
// Covariance allows this delegate.
HandlerMethod handler2 = SecondHandler;
}
}
#endregion
#region 委托中的逆变,方法的参数是委托的参数的基类
class NiBianDelegate
{
public delegate Dogs HandlerNibianMethod(Dogs dogs);
public Dogs FirstHandlerNibian(Mammals mammals)
{
return null;
}
void Test()
{
Dogs dogs = new Dogs();
HandlerNibianMethod handNibian1 = FirstHandlerNibian;
}
}
#endregion
五、委托综合示例(来自MSDN)
下面的示例阐释声明、实例化和使用委托。BookDB 类封装一个书店数据库,它维护一个书籍数据库。它公开 ProcessPaperbackBooks 方法,该方法在数据库中查找所有平装书,并对每本平装书调用一个委托。使用的 delegate 类型名为 ProcessBookDelegate。Test 类使用该类打印平装书的书名和平均价格。
委托的使用促进了书店数据库和客户代码之间功能的良好分隔。客户代码不知道书籍的存储方式和书店代码查找平装书的方式。书店代码也不知道找到平装书后将对平装书执行什么处理。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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:
public class TestBookDB
{
// Print the title of the book.
void PrintTitle(Book b)
{
System.Console.WriteLine(" {0}", b.Title);
}
// Execution starts here.
public void Test()
{
BookDB bookDB = new BookDB();
// Initialize the database with some books:
AddBooks(bookDB);
// Print all the titles of paperbacks:
System.Console.WriteLine("Paperback Book Titles:");
// Create a new delegate object associated with the static
// method Test.PrintTitle:
bookDB.ProcessPaperbackBooks(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(totaller.AddBookToTotal);
System.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);
}
}
}
扫码关注公众号,了解更多管理,见识,育儿等内容
出处:http://www.cnblogs.com/cnblogsfans
版权:本文版权归作者所有,转载需经作者同意。