举例讲解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方法同步或异步调用委托。