表示委托,委托是一种数据结构,它引用静态方法或引用类实例及该类的实例方法。
[SerializableAttribute]
[ClassInterfaceAttribute(ClassInterfaceType.AutoDual)]
[ComVisibleAttribute(true)]
public abstract class Delegate : ICloneable, ISerializable
Delegate 类是委托类型的基类。然而,只有系统和编译器可以显式地从 Delegate 类或MulticastDelegate 类派生。此外,还不允许从委托类型派生新类型。Delegate 类不是委托类型,该类用于派生委托类型。
大多数语言实现 delegate 关键字,这些语言的编译器能够从 MulticastDelegate 类进行派生;所以,用户应当使用语言所提供的delegate 关键字。
委托类型的声明建立了一个协定,该协定指定一个或多个方法的签名。委托是具有对以下内容的引用的委托类型的实例:
-
某种类型的实例方法和可分配给该类型的目标对象。
-
某种类型的实例方法(包含在形参表中公开的隐藏 this 参数)。该委托称为开放式实例委托。
-
静态方法。
-
静态方法和可分配给该方法的第一个参数的目标对象。该委托称为通过其第一个参数关闭。
当委托表示通过其第一个参数关闭的实例方法(最常见的情况)时,委托存储对该方法的入口点的引用和对称为目标的对象(该对象具有可分配给定义该方法的类型的类型)的引用。当委托表示开放式实例方法时,它存储对该方法入口点的引用。委托签名必须在其形参表中包括隐藏的this 参数;在这种情况下,委托不具有对目标对象的引用,必须在调用委托时提供目标对象。
当委托表示静态方法时,委托存储对该方法入口点的引用。当委托表示通过其第一个参数关闭的静态方法时,委托存储对该方法入口点的引用和对目标对象(该对象可分配给方法第一个参数的类型)的引用。调用该委托时,静态方法的第一个参数接收目标对象。
委托的调用列表就是已排序的委托集,其中列表的每个元素恰好调用该委托表示的一个方法。调用列表可以包含重复的方法。在调用期间,按方法出现在调用列表中的顺序来调用它们。委托试图调用其调用列表中的每个方法,而重复方法在调用列表中出现一次就调用一次。委托是不可变的;一旦创建,委托的调用列表便无法更改。
委托被称作多路广播委托或可组合委托,因为委托可以调用一种或多种方法,并且可以用在组合操作中。
合并操作(如 Combine 和 Remove)并不改变现有委托。相反,这样的操作返回一个新委托,其中包含操作结果、未更改的委托或 空引用(在 Visual Basic 中为 Nothing)。当合并操作的结果是没有引用任何方法的委托时,该操作返回 空引用(在 Visual Basic 中为 Nothing)。当所请求的操作无效时,合并操作返回未更改的委托。
如果所调用的方法引发异常,则方法停止执行,并将异常向回传递给委托的调用方,且不再调用调用列表中其余的方法。捕捉调用方的异常并不改变此行为。
当委托所调用的方法的签名包含返回值时,委托返回调用列表中最后一个元素的返回值。当签名包含由引用传递的参数时,该参数的最终值就是调用列表中每个方法的结果,这些方法依序执行并更新参数的值。
编译器为委托提供两种其他方法:BeginInvoke 和 EndInvoke。有关这些方法的更多信息,请参见“使用异步方式调用同步方法”。
在 C 或 C++ 中与委托最为相似的是函数指针。委托可以表示静态方法或实例方法。当委托表示实例方法时,委托不仅存储对方法入口点的引用,还存储对类实例的引用。与函数指针不同,委托是面向对象和类型安全的。
using System;
public class SamplesDelegate {
// Declares a delegate for a method that takes in an int and returns a String.
public delegate String myMethodDelegate( int myInt );
// Defines some methods to which the delegate can point.
public class mySampleClass {
// Defines an instance method.
public String myStringMethod ( int myInt ) {
if ( myInt > 0 )
return( "positive" );
if ( myInt < 0 )
return( "negative" );
return ( "zero" );
}
// Defines a static method.
public static String mySignMethod ( int myInt ) {
if ( myInt > 0 )
return( "+" );
if ( myInt < 0 )
return( "-" );
return ( "" );
}
}
public static void Main() {
// Creates one delegate for each method.
mySampleClass mySC = new mySampleClass();
myMethodDelegate myD1 = new myMethodDelegate( mySC.myStringMethod );
myMethodDelegate myD2 = new myMethodDelegate( mySampleClass.mySignMethod );
// Invokes the delegates.
Console.WriteLine( "{0} is {1}; use the sign \"{2}\".", 5, myD1( 5 ), myD2( 5 ) );
Console.WriteLine( "{0} is {1}; use the sign \"{2}\".", -3, myD1( -3 ), myD2( -3 ) );
Console.WriteLine( "{0} is {1}; use the sign \"{2}\".", 0, myD1( 0 ), myD2( 0 ) );
}
}