举例讲解C#编程中委托的实例化使用
合并委托
本示例演示如何创建多播委托。委托对象的一个有用属性是:可以使用+运算符将多个对象分配给一个委托实例。多播委托包含已分配委托的列表。在调用多播委托时,它会按顺序调用列表中的委托。只能合并相同类型的委托。
-运算符可用于从多播委托中移除组件委托。
usingSystem;
//Defineacustomdelegatethathasastringparameterandreturnsvoid.
delegatevoidCustomDel(strings);
classTestClass
{
//DefinetwomethodsthathavethesamesignatureasCustomDel.
staticvoidHello(strings)
{
System.Console.WriteLine("Hello,{0}!",s);
}
staticvoidGoodbye(strings)
{
System.Console.WriteLine("Goodbye,{0}!",s);
}
staticvoidMain()
{
//Declareinstancesofthecustomdelegate.
CustomDelhiDel,byeDel,multiDel,multiMinusHiDel;
//Inthisexample,youcanomitthecustomdelegateifyou
//wanttoanduseAction<string>instead.
//Action<string>hiDel,byeDel,multiDel,multiMinusHiDel;
//CreatethedelegateobjecthiDelthatreferencesthe
//methodHello.
hiDel=Hello;
//CreatethedelegateobjectbyeDelthatreferencesthe
//methodGoodbye.
byeDel=Goodbye;
//Thetwodelegates,hiDelandbyeDel,arecombinedto
//formmultiDel.
multiDel=hiDel+byeDel;
//RemovehiDelfromthemulticastdelegate,leavingbyeDel,
//whichcallsonlythemethodGoodbye.
multiMinusHiDel=multiDel-hiDel;
Console.WriteLine("InvokingdelegatehiDel:");
hiDel("A");
Console.WriteLine("InvokingdelegatebyeDel:");
byeDel("B");
Console.WriteLine("InvokingdelegatemultiDel:");
multiDel("C");
Console.WriteLine("InvokingdelegatemultiMinusHiDel:");
multiMinusHiDel("D");
}
}
输出:
InvokingdelegatehiDel: Hello,A! InvokingdelegatebyeDel: Goodbye,B! InvokingdelegatemultiDel: Hello,C! Goodbye,C! InvokingdelegatemultiMinusHiDel: Goodbye,D!
声明、实例化和使用委托
在C#1.0及更高版本中,可以按以下示例所示声明委托。
//Declareadelegate.
delegatevoidDel(stringstr);
//Declareamethodwiththesamesignatureasthedelegate.
staticvoidNotify(stringname)
{
Console.WriteLine("Notificationreceivedfor:{0}",name);
}
//Createaninstanceofthedelegate.
Deldel1=newDel(Notify);
C#2.0提供了更简单的方法来编写上面的声明,如以下示例所示。
//C#2.0providesasimplerwaytodeclareaninstanceofDel. Deldel2=Notify;
在C#2.0及更高版本中,还可以使用匿名方法来声明和初始化委托,如以下示例所示。
//InstantiateDelbyusingananonymousmethod.
Deldel3=delegate(stringname)
{Console.WriteLine("Notificationreceivedfor:{0}",name);};
在C#3.0及更高版本中,还可以使用Lambda表达式来声明和实例化委托,如以下示例所示。
//InstantiateDelbyusingalambdaexpression.
Deldel4=name=>{Console.WriteLine("Notificationreceivedfor:{0}",name);};
下面的示例阐释声明、实例化和使用委托。BookDB类封装一个书店数据库,它维护一个书籍数据库。它公开ProcessPaperbackBooks方法,该方法在数据库中查找所有平装书,并对每本平装书调用一个委托。使用的delegate类型名为ProcessBookDelegate。Test类使用该类打印平装书的书名和平均价格。
委托的使用促进了书店数据库和客户代码之间功能的良好分隔。客户代码不知道书籍的存储方式和书店代码查找平装书的方式。书店代码也不知道找到平装书后将对平装书执行什么处理。
//Asetofclassesforhandlingabookstore:
namespaceBookstore
{
usingSystem.Collections;
//Describesabookinthebooklist:
publicstructBook
{
publicstringTitle;//Titleofthebook.
publicstringAuthor;//Authorofthebook.
publicdecimalPrice;//Priceofthebook.
publicboolPaperback;//Isitpaperback?
publicBook(stringtitle,stringauthor,decimalprice,boolpaperBack)
{
Title=title;
Author=author;
Price=price;
Paperback=paperBack;
}
}
//Declareadelegatetypeforprocessingabook:
publicdelegatevoidProcessBookDelegate(Bookbook);
//Maintainsabookdatabase.
publicclassBookDB
{
//Listofallbooksinthedatabase:
ArrayListlist=newArrayList();
//Addabooktothedatabase:
publicvoidAddBook(stringtitle,stringauthor,decimalprice,boolpaperBack)
{
list.Add(newBook(title,author,price,paperBack));
}
//Callapassed-indelegateoneachpaperbackbooktoprocessit:
publicvoidProcessPaperbackBooks(ProcessBookDelegateprocessBook)
{
foreach(Bookbinlist)
{
if(b.Paperback)
//Callingthedelegate:
processBook(b);
}
}
}
}
//UsingtheBookstoreclasses:
namespaceBookTestClient
{
usingBookstore;
//Classtototalandaveragepricesofbooks:
classPriceTotaller
{
intcountBooks=0;
decimalpriceBooks=0.0m;
internalvoidAddBookToTotal(Bookbook)
{
countBooks+=1;
priceBooks+=book.Price;
}
internaldecimalAveragePrice()
{
returnpriceBooks/countBooks;
}
}
//Classtotestthebookdatabase:
classTestBookDB
{
//Printthetitleofthebook.
staticvoidPrintTitle(Bookb)
{
System.Console.WriteLine("{0}",b.Title);
}
//Executionstartshere.
staticvoidMain()
{
BookDBbookDB=newBookDB();
//Initializethedatabasewithsomebooks:
AddBooks(bookDB);
//Printallthetitlesofpaperbacks:
System.Console.WriteLine("PaperbackBookTitles:");
//Createanewdelegateobjectassociatedwiththestatic
//methodTest.PrintTitle:
bookDB.ProcessPaperbackBooks(PrintTitle);
//Gettheaveragepriceofapaperbackbyusing
//aPriceTotallerobject:
PriceTotallertotaller=newPriceTotaller();
//Createanewdelegateobjectassociatedwiththenonstatic
//methodAddBookToTotalontheobjecttotaller:
bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);
System.Console.WriteLine("AveragePaperbackBookPrice:${0:#.##}",
totaller.AveragePrice());
}
//Initializethebookdatabasewithsometestbooks:
staticvoidAddBooks(BookDBbookDB)
{
bookDB.AddBook("TheCProgrammingLanguage","BrianW.KernighanandDennisM.Ritchie",19.95m,true);
bookDB.AddBook("TheUnicodeStandard2.0","TheUnicodeConsortium",39.95m,true);
bookDB.AddBook("TheMS-DOSEncyclopedia","RayDuncan",129.95m,false);
bookDB.AddBook("Dogbert'sCluesfortheClueless","ScottAdams",12.00m,true);
}
}
}
输出:
PaperbackBookTitles: TheCProgrammingLanguage TheUnicodeStandard2.0 Dogbert'sCluesfortheClueless AveragePaperbackBookPrice:$23.97
可靠编程
声明委托。
下面的语句声明一个新的委托类型。
publicdelegatevoidProcessBookDelegate(Bookbook);
每个委托类型都描述参数的数目和类型,以及它可以封装的方法的返回值类型。每当需要一组新的参数类型或新的返回值类型时,都必须声明一个新的委托类型。
实例化委托。
声明了委托类型后,必须创建委托对象并使之与特定方法关联。在上一个示例中,您通过按下面示例中的方式将PrintTitle方法传递到ProcessPaperbackBooks方法来实现这一点:
bookDB.ProcessPaperbackBooks(PrintTitle);
这将创建与静态方法Test.PrintTitle关联的新委托对象。类似地,对象totaller的非静态方法AddBookToTotal是按下面示例中的方式传递的:
bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);
在两个示例中,都向ProcessPaperbackBooks方法传递了一个新的委托对象。
委托创建后,它的关联方法就不能更改;委托对象是不可变的。
调用委托。
创建委托对象后,通常将委托对象传递给将调用该委托的其他代码。通过委托对象的名称(后面跟着要传递给委托的参数,括在括号内)调用委托对象。下面是委托调用的示例:
processBook(b);
与本例一样,可以通过使用BeginInvoke和EndInvoke方法同步或异步调用委托。