C#编程指南委托Word下载.docx
- 文档编号:22409065
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:17
- 大小:22.10KB
C#编程指南委托Word下载.docx
《C#编程指南委托Word下载.docx》由会员分享,可在线阅读,更多相关《C#编程指南委托Word下载.docx(17页珍藏版)》请在冰豆网上搜索。
以这种方式使用委托时,使用委托的代码无需了解有关所用方法的实现方面的任何信息。
此功能类似于接口所提供的封装。
有关更多信息,请参见何时使用委托而不使用接口。
回调的另一个常见用法是定义自定义的比较方法并将该委托传递给排序方法。
它允许调用方的代码成为排序算法的一部分。
下面的示例方法使用Del类型作为参数:
publicvoidMethodWithCallback(intparam1,intparam2,Delcallback)
callback("
Thenumberis:
"
+(param1+param2).ToString());
然后可以将上面创建的委托传递给该方法:
MethodWithCallback(1,2,handler);
在控制台中将收到下面的输出:
3
在将委托用作抽象概念时,MethodWithCallback不需要直接调用控制台--设计它时无需考虑控制台。
MethodWithCallback的作用只是准备字符串并将该字符串传递给其他方法。
此功能特别强大,因为委托的方法可以使用任意数量的参数。
将委托构造为包装实例方法时,该委托将同时引用实例和方法。
除了它所包装的方法外,委托不了解实例类型,所以只要任意类型的对象中具有与委托签名相匹配的方法,委托就可以引用该对象。
将委托构造为包装静态方法时,它只引用方法。
考虑下列声明:
publicclassMethodClass
publicvoidMethod1(stringmessage){}
publicvoidMethod2(stringmessage){}
加上前面显示的静态DelegateMethod,现在我们有三个方法可由Del实例进行包装。
调用委托时,它可以调用多个方法。
这称为多路广播。
若要向委托的方法列表(调用列表)中添加额外的方法,只需使用加法运算符或加法赋值运算符(“+”或“+=”)添加两个委托。
MethodClassobj=newMethodClass();
Deld1=obj.Method1;
Deld2=obj.Method2;
Deld3=DelegateMethod;
//Bothtypesofassignmentarevalid.
DelallMethodsDelegate=d1+d2;
allMethodsDelegate+=d3;
此时,allMethodsDelegate在其调用列表中包含三个方法--Method1、Method2和DelegateMethod。
原来的三个委托d1、d2和d3保持不变。
调用allMethodsDelegate时,将按顺序调用所有这三个方法。
如果委托使用引用参数,则引用将依次传递给三个方法中的每个方法,由一个方法引起的更改对下一个方法是可见的。
如果任一方法引发了异常,而在该方法内未捕获该异常,则该异常将传递给委托的调用方,并且不再对调用列表中后面的方法进行调用。
如果委托具有返回值和/或输出参数,它将返回最后调用的方法的返回值和参数。
若要从调用列表中移除方法,请使用减法运算符或减法赋值运算符(“-”或“-=”)。
//removeMethod1
allMethodsDelegate-=d1;
//copyAllMethodsDelegatewhileremovingd2
DeloneMethodDelegate=allMethodsDelegate-d2;
由于委托类型派生自System.Delegate,所以可在委托上调用该类定义的方法和属性。
例如,为了找出委托的调用列表中的方法数,您可以编写下面的代码:
intinvocationCount=d1.GetInvocationList().GetLength(0);
在调用列表中具有多个方法的委托派生自MulticastDelegate,这是System.Delegate的子类。
由于两个类都支持GetInvocationList,所以上面的代码在两种情况下都适用。
多路广播委托广泛用于事件处理中。
事件源对象向已注册接收该事件的接收方对象发送事件通知。
为了为事件注册,接收方创建了旨在处理事件的方法,然后为该方法创建委托并将该委托传递给事件源。
事件发生时,源将调用委托。
然后,委托调用接收方的事件处理方法并传送事件数据。
给定事件的委托类型由事件源定义。
有关更多信息,请参见事件(C#编程指南)。
在编译时,对分配了两种不同类型的委托进行比较将产生编译错误。
如果委托实例静态地属于类型System.Delegate,则允许进行比较,但在运行时将返回false。
delegatevoidDelegate1();
delegatevoidDelegate2();
staticvoidmethod(Delegate1d,Delegate2e,System.Delegatef)
//Compile-timeerror.
//Console.WriteLine(d==e);
//OKatcompile-time.Falseiftherun-timetypeoff
//isnotthesameasthatofd.
System.Console.WriteLine(d==f);
二、带有命名方法的委托与带有匿名方法的委托
委托可以与命名方法关联。
使用命名方法对委托进行实例化时,该方法将作为参数传递,例如:
//Declareadelegate:
delegatevoidDel(intx);
//Defineanamedmethod:
voidDoWork(intk){/*...*/}
//Instantiatethedelegateusingthemethodasaparameter:
Deld=obj.DoWork;
这被称为使用命名的方法。
使用命名方法构造的委托可以封装静态方法或实例方法。
在早期版本的C#中,命名方法是对委托进行实例化的唯一方式。
但是,在不希望付出创建新方法的系统开销时,C#使您可以对委托进行实例化,并立即指定委托在被调用时将处理的代码块。
这些被称为匿名方法(C#编程指南)。
备注
作为委托参数传递的方法必须与委托声明具有相同的签名。
委托实例可以封装静态或实例方法。
尽管委托可以使用out参数,但建议您不要将其用于多路广播事件委托,因为您无法知道哪个委托将被调用。
示例1
以下是声明及使用委托的一个简单示例。
注意,委托Del和关联的方法MultiplyNumbers具有相同的签名
//Declareadelegate
delegatevoidDel(inti,doublej);
classMathClass
staticvoidMain()
{
MathClassm=newMathClass();
//Delegateinstantiationusing"
MultiplyNumbers"
Deld=m.MultiplyNumbers;
//Invokethedelegateobject.
System.Console.WriteLine("
Invokingthedelegateusing'
MultiplyNumbers'
:
"
for(inti=1;
i<
=5;
i++)
d(i,2);
}
//Declaretheassociatedmethod.
voidMultiplyNumbers(intm,doublen)
System.Console.Write(m*n+"
输出
246810
示例2
在下面的示例中,一个委托被同时映射到静态方法和实例方法,并分别返回特定的信息。
delegatevoidDel();
classSampleClass
publicvoidInstanceMethod()
Amessagefromtheinstancemethod."
staticpublicvoidStaticMethod()
Amessagefromthestaticmethod."
classTestSampleClass
SampleClasssc=newSampleClass();
//Mapthedelegatetotheinstancemethod:
Deld=sc.InstanceMethod;
d();
//Maptothestaticmethod:
d=SampleClass.StaticMethod;
Amessagefromtheinstancemethod.
Amessagefromthestaticmethod.
三、何时使用委托而不使用接口
委托和接口都允许类设计器分离类型声明和实现。
任何类或结构都能继承和实现给定的接口。
可以为任何类上的方法创建委托,前提是该方法符合委托的方法签名。
接口引用或委托可由不了解实现该接口或委托方法的类的对象使用。
既然存在这些相似性,那么类设计器何时应使用委托,何时又该使用接口呢?
在以下情况下,请使用委托:
当使用事件设计模式时。
当封装静态方法可取时。
当调用方不需要访问实现该方法的对象中的其他属性、方法或接口时。
需要方便的组合。
当类可能需要该方法的多个实现时。
在以下情况下,请使用接口:
当存在一组可能被调用的相关方法时。
当类只需要方法的单个实现时。
当使用接口的类想要将该接口强制转换为其他接口或类类型时。
当正在实现的方法链接到类的类型或标识时:
例如比较方法。
使用单一方法接口而不使用委托的一个很好的示例是IComparable或泛型版本IComparable<
(Of<
(T>
)>
)。
IComparable声明CompareTo方法,该方法返回一个整数,指定相同类型的两个对象之间的小于、等于或大于关系。
IComparable可用作排序算法的基础。
虽然将委托比较方法用作排序算法的基础是有效的,但是并不理想。
因为进行比较的能力属于类,而比较算法不会在运行时改变,所以单一方法接口是理想的。
四、委托中的协变和逆变
将方法签名与委托类型匹配时,协变和逆变可以提供一定程度的灵活性。
协变允许方法具有的派生返回类型比委托中定义的更多。
逆变允许方法具有的派生参数类型比委托类型中的更少。
示例1(协变)
说明
本示例演示如何将委托与具有返回类型的方法一起使用,这些返回类型派生自委托签名中的返回类型。
由SecondHandler返回的数据类型是Dogs类型,它是由委托中定义的Mammals类型派生的。
代码
classMammals
classDogs:
Mammals
classProgram
//Definethedelegate.
publicdelegateMammalsHandlerMethod();
publicstaticMammalsFirstHandler()
returnnull;
publicstaticDogsSecondHandler()
HandlerMethodhandler1=FirstHandler;
//Covarianceallowsthisdelegate.
HandlerMethodhandler2=SecondHandler;
示例2(逆变)
本示例演示如何将委托与具有某个类型的参数的方法一起使用,这些参数是委托签名参数类型的基类型。
通过逆变,以前必须使用若干个不同处理程序的地方现在只要使用一个事件处理程序即可。
如,现在可以创建一个接收EventArgs输入参数的事件处理程序,然后,可以将该处理程序与发送MouseEventArgs类型(作为参数)的Button.MouseClick事件一起使用,也可以将该处理程序与发送KeyEventArgs参数的TextBox.KeyDown事件一起使用。
System.DateTimelastActivity;
publicForm1()
InitializeComponent();
lastActivity=newSystem.DateTime();
this.textBox1.KeyDown+=this.MultiHandler;
//workswithKeyEventArgs
this.button1.MouseClick+=this.MultiHandler;
//workswithMouseEventArgs
//EventhanderforanyeventwithanEventArgsor
//derivedclassinthesecondparameter
privatevoidMultiHandler(objectsender,System.EventArgse)
lastActivity=System.DateTime.Now;
五、如何:
合并委托(多路广播委托)
本示例演示如何组合多路广播委托。
委托对象的一个用途在于,可以使用+运算符将它们分配给一个要成为多路广播委托的委托实例。
组合的委托可调用组成它的那两个委托。
只有相同类型的委托才可以组合。
-运算符可用来从组合的委托移除组件委托。
示例
delegatevoidDel(strings);
classTestClass
staticvoidHello(strings)
Hello,{0}!
s);
staticvoidGoodbye(strings)
Goodbye,{0}!
Dela,b,c,d;
//Createthedelegateobjectathatreferences
//themethodHello:
a=Hello;
//Createthedelegateobjectbthatreferences
//themethodGoodbye:
b=Goodbye;
//Thetwodelegates,aandb,arecomposedtoformc:
c=a+b;
//Removeafromthecomposeddelegate,leavingd,
//whichcallsonlythemethodGoodbye:
d=c-a;
Invokingdelegatea:
a("
A"
Invokingdelegateb:
b("
B"
Invokingdelegatec:
c("
C"
Invokingdelegated:
d("
D"
复制代码
Hello,A!
Goodbye,B!
Hello,C!
Goodbye,C!
Goodbye,D!
六、如何:
声明、实例化和使用委托
在C#1.0及更高版本中,可以按此处所示方式声明委托:
publicdelegatevoidDel<
T>
(Titem);
publicvoidNotify(inti){}
Del<
int>
d1=newDel<
(Notify);
在C#2.0及更高版本中,还可以使用以下简化的语法,通过匿名方法来声明和初始化委托:
d2=Notify;
在C#3.0及更高版本中,还可以使用Lambda表达式来声明和实例化委托。
有关更多信息,请参见Lambda表达式(C#编程指南)。
下面的示例阐释声明、实例化和使用委托。
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(ProcessBookDelegatep
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C# 编程 指南 委托