日期:2012-08-02  浏览次数:20488 次

C#语言系列讲座
委派


--------------------------------------------------------------------------------


委派

委派是C#引入的一种新的数据类型,它非常类似于C/C++中的函数指针,常常用于在编译时未绑定的动态方法调用。与函数指针不同的是委派在C#中完全实现了面向对象,它既可以引用静态方法,也可以引用实例方法,而函数指针只能引用静态方法。C#中的委派同时也是类型安全的。

作为一种面向对象的数据类型,委派的使用分为三步:委派声明,委派实例化和委派调用。委派声明就是定义一个封装特定参数类型和返回值类型的方法体(静态方法或实例方法)的数据类型,看下面的示例:

delegate int Compute (int left, int right);

可以看到,委派类型Compute包含了方法的两个要素: 参数类型和返回值类型。委派类型和方法只有满足下面两个条件,才能说它们是兼容的:

1. 参数的数量相同,并且它们的类型也按顺序相同;

2. 返回值相同。

委派类型相同指的是它们声明的类型为同一类型(名字一样)。而委派实例相等则是指它们绑定的方法为同一个方法,或相同的方法按相同的顺序组成的方法链,而它们本身的类型只要兼容即可(同样满足上面两个条件),不必强求同名。

委派实例化就是将委派类型绑定到特定方法的过程,和其他对象的实例化相似,都需要用new语句,只是必须接受和该委派类型兼容的方法名作为new语句的参数。如果是实例方法,必须采用两者中间加点号的方式同时提供实例对象和方法。

委派实例化后就可以像调用方法一样进行委派调用了。下面是一个完整的例子,比较典型地展示了通常使用委派的三个步骤:

using System;

delegate int Compute(int left, int right);

//委派类型声明

class A

{

public int Mul(int num1, int num2)

{ return num1*num2;

}

}

class Test

{

public static int Add(int num1, int num2)

{ return num1+num2;

}

static void Main()

{ Compute c1=new Compute(Add);

//静态方法的实例化

A a=new A();

Compute c2=new Compute(a.Mul);

//实例方法的实例化

int r1=c1(2,3);//委派调用

int r2=c2(2,3);//委派调用

Console.WriteLine(r1);

Console.WriteLine(r2);

}

}

委派组合

委派组合是指一个委派类型可以同时绑定多个可调用的方法。由于绑定多个方法,C#规定组合委派的返回类型必须为void。当然,这些方法的参数类型也必须都和组合委派的参数类型兼容。委派组合采用“+”或“+=”来将两个委派类型合并为一个新的组合委派类型; 采用“-”或“-=”来从组合委派类型上移除已经绑定一个方法的委派实例或绑定多个方法的组合委派实例。

需要注意的是在做委派的组合和移除操作的时候,参与操作的委派类型必须相同——注意是“相同”不是“相等”。看下面的例子:

using System;

delegate void MyDelegate(string s);

class Test

{

public static void Hello(string s)

{

Console.WriteLine(“Hello, {0}!”, s);

}

public static void Goodbye(string s)

{

Console.WriteLine(“Goodbye, {0}!”, s);

}

public static void Main()

{

MyDelegate a, b, c, d;

a = new MyDelegate(Hello);

b =new MyDelegate(Goodbye);

c = a + b;//委派的组合

d = c - a;//委派的移除

a(“A”);

b(“B”);

c(“C”);

d(“D”);

}

}

程序输出:

Hello, A!

Goodbye, B!

Hello, C!

Goodbye, C!

Goodbye, D!

可以看到在委派组合后,组合委派类型C同时绑定了两个方法Hello(string s)和Goodbye(string s),从它的输出可以看到这一点。

需要注意的是组合委派中的方法调用是有顺序的,如果在上面的例子中修改“c = a + b; ”为“c=b + a; ”,将看到输出序列的改变。

同样委派的移除也是有顺序的,它总是从绑定的委派实例中的最后开始搜索需要移出的委派实例——注意这里的移除是以委派实例为单位的,而不是以方法为单位。可以将上面的例子进行修改,再看看结果:

public static void Main()

{

MyDelegate a, b, c, d;

a = new MyDelegate(Hello);

b =new MyDelegate(Goodbye);

c = a+b+a;//委派的组合

b+=b;//委派的组合

d = c - b;//委派的移除

a(“A”);

b(“B”);

c(“C”);

d(“D”);

}