1、委托可确保回调方法是类型安全的;
2、委托可以顺序调用多个方法,并支持静态方法和实例方法;
3、委托封装实例方法是非常有用的,因为对象内部的代码可以访问对象的实例方法成员,这就意味着对象可以维护一些状态,并且在回调方法执行期间用到这种状态;
4、委托实际上是类,因为编译器会为委托生成一个完整的类,所以在可以定义类的地方,就可以定义委托;
5、Delegate类定义了两个只读的公共实例属性:Target和Method;Target返回一个对象引用,该对象就是方法回调时要操作的那个对象,如果委托对象封装了一个静态方法,那么Target将返回Null;Method属性返回一个System.Reflection.MethodInfo对象引用(标识回调方法);
协变(convariance):指的是一个方法返回从委托的返回类型派生的一个类型;
反协变(contra-variance):指的是一个方法的参数类型可以是委托的参数类型的基类型;
internal delegate object MyCallback(int s);
public class Delegate_covariance_contra_variance
{
private static string SomeMethod(object s)
{
Console.WriteLine(s.ToString());
return s.ToString();
}
public static void Test()
{
//Error:“SomeMethod(object)”的重载均与委托“MyCallback”不匹配
MyCallback call = new MyCallback(SomeMethod);
call(1);
}
上面的代码编译时会出错,分析一下:
首先,SomeMethod的返回类型(String)是继承自委托返回类型(Object),所以这种协变是允许的;
其次,SomeMethod的参数类型(Object)是委托的参数类型(int)的基类,符合
反协变的定义,但是这种反协变是无法通过编译的,因为协变与反协变都不支持值类型和Void:因为值类型和void的存储结构式变化的,而引用类型的存储结构始终是一个指针;
最后,修改方法就是将委托的参数类型改为引用类型。
internal delegate object MyCallback(string s);
委托链调用要注意两个问题:
1、 除最后一个返回值之外,回调方法的所有返回值都会被丢弃;
2、 如果被调用的委托中有一个抛出了异常或者堵塞了相当长一段时间,就会停止调用后续所有对象。
为此,MulticastDelegate类提供了一个实例方法GetInvocationList,
private static String GetComponentStatusReport(GetStatus status) {
// If the chain is empty, there抯is nothing to do.
if (status == null) return null;
// Use this to build the status report.
StringBuilder report = new StringBuilder();
// Get an array where each element is a delegate from the chain.
Delegate[] arrayOfDelegates = status.GetInvocationList();
// Iterate over each delegate in the array.
foreach (GetStatus getStatus in arrayOfDelegates) {
try {
// Get a component's status string, and append it to the report.
report.AppendFormat("{0} {1} {2}", getStatus(),getStatus.Target+":"+getStatus.Method, Environment.NewLine);
}
catch (InvalidOperationException e) {
// Generate an error entry in the report for this component.
Object component = getStatus.Target;
report.AppendFormat(
"Failed to get status from {1}{2}{0} Error: {3}{0}{0}",
Environment.NewLine,
((component == null) ? "" : component.GetType() + "."),
getStatus.Method.Name, e.Message);
}
}
// Return the consolidated report to the caller.
return report.ToString();
}
C#为委托提供的语法便利
主要介绍了委托的简便写法,这里有一个定义匿名方法(anonymous method),要注意三点:
1、 在编写匿名方法的时候,在代码中的delegate关键字后加入这个指定名称(Object obj);
internal sealed class AClass {
private static void CallbackWithoutNewingADelegateObject() {
ThreadPool.QueueUserWorkItem(
delegate(Object obj) { Console.WriteLine(obj); }, 5);
}
}
2、 匿名方法标识为private,这会禁止在类型内部定义的任何代码访问这个方法;
匿名方法标识为static,这是因为代码没有访问任何实例方法成员,不过,代码可以引用类中定义的静态字段或静态方法;
internal sealed class AClass {
private static string m_str;
private static void CallbackWithoutNewingADelegateObject() {
ThreadPool.QueueUserWorkItem(
delegate(Object obj) { Console.WriteLine( m_str+":"+obj); }, 5);
}
}
3、 如果CallbackWithoutNewingADelegateObject方法不是静态的,那么匿名方法的代码就可以包含对实例成员的引用;
internal sealed class AClass {
private int m_i;
private void CallbackWithoutNewingADelegateObject1()
{
ThreadPool.QueueUserWorkItem(
delegate(Object obj) { Console.WriteLine(m_i + ":" + obj); }, 5);
}
}