委托提供了类似C++中函数指针的功能,简单地说委托类型就是面向对象函数指针,
不过C++的函数指针只能够指向静态的方法,
而委托除了可以指向一个静态的方法之外还可以指向对象实例的方法,并且委托是完全面向对象且使用安全的类型。
也就是说:委托可以看成是一种类型安全的函数指针,它用来代理一类符合其要求的方法(包括静态方法和动态方法即实例的方法),同时它又可以作为一个方法的参数进行传。
对“符合其要求”的解释:委托的 返回类型 和 参数 要与被代理的方法的 返回类型 和 参数 一致(不仅类型一致,参数个数也要相同)。
委托的优点:委托允许程序设计师可以在执行时期传入方法的名称动态地决定欲调用的方法,灵活性和扩张性非常强。
委托一般用在事件、多线程和通用类库中。
下面列举了5个示例对委托的概念和基本用法进行说明(这些例子来自陈广老师和楚广明老师的课堂,自己稍作了修改和融合)
为了省去创建GUI那些繁琐的步骤,更清晰地逼近委托的本质,接下来的所有程序都是控制台程序,程序最后的Console.ReadKey()是为了使程序中途停下来,以便看清楚执行过程中的输出。
一、
View Code
using
System;
//
一、代理静态方法示例
namespace
DelegateDemo {
//
委托的本质就是一个类,任何可以声明类的地方都可以声明委托
delegate
void
EatDelegate(
string
food);
//
委托的声明;其返回类型和参数要与被代理的方法的返回类型和参数一致
class
MyDelegate {
static
void
ZsEat(
string
food)
//
被代理的方法
{ Console.WriteLine(
"
张三吃:
"
+
food); }
static
void
LsEat(
string
food)
//
被代理的方法
{ Console.WriteLine(
"
李四吃:
"
+
food); }
static
void
WwEat(
string
food)
//
被代理的方法
{ Console.WriteLine(
"
王五吃:
"
+
food); }
static
void
Main(
string
[] args) { EatDelegate zsEat
=
new
EatDelegate(ZsEat);
//
委托的实例化;代理的静态方法
zsEat(
"
西瓜
"
);
//
委托的使用;
EatDelegate lsEat
=
LsEat;
//
代理的静态方法,直接将方法名传递给委托变量
lsEat(
"
香蕉
"
); EatDelegate wwEat
=
new
EatDelegate(WwEat);
//
委托的实例化;代理的静态方法
EatDelegate eatChain; Console.WriteLine(
"
张三、李四、王五开座谈会
"
); eatChain
=
zsEat
+
lsEat
+
wwEat;
//
委托链
eatChain(
"
西瓜
"
); Console.WriteLine(); Console.WriteLine(
"
李四出去接电话
"
); eatChain
-=
lsEat; eatChain(
"
香蕉
"
); Console.WriteLine(); Console.WriteLine(
"
李四回来了
"
); eatChain
+=
lsEat; eatChain(
"
橘子
"
); Console.WriteLine(); Console.WriteLine(
"
这是赵六来了
"
); eatChain
+=
delegate
(
string
food) { Console.WriteLine(
"
赵六吃:
"
+
food); };
//
匿名方法;
eatChain(
"
苹果
"
); Console.ReadKey(); } } }
输出结果:
二、
View Code
using
System;
//
二、代理动态方法示例
namespace
DelegateDemo {
//
委托的本质就是一个类,任何可以声明类的地方都可以声明委托
delegate
void
EatDelegate(
string
food);
//
委托的声明;其返回类型和参数要与被代理的方法的返回类型和参数一致
class
Man {
private
string
name;
public
Man(
string
name) {
this
.name
=
name; }
public
void
Eat(
string
food)
//
被代理的方法
{ Console.WriteLine(name
+
"
吃:
"
+
food); } }
class
MyDelegate {
static
void
Main(
string
[] args) { Man zs
=
new
Man(
"
张三
"
); Man ls
=
new
Man(
"
李四
"
); Man ww
=
new
Man(
"
王五
"
); EatDelegate zsEat
=
new
EatDelegate(zs.Eat);
//
委托的实例化;代理的动态方法,即实例的方法
zsEat(
"
西瓜
"
);
//
委托的使用;
EatDelegate lsEat
=
ls.Eat;
//
代理的动态方法,直接将实例的方法名传递给委托变量
lsEat(
"
香蕉
"
); EatDelegate wwEat
=
new
EatDelegate(ww.Eat);
//
委托的实例化;代理的动态方法
EatDelegate eatChain; Console.WriteLine(
"
张三、李四、王五开座谈会
"
); eatChain
=
zsEat
+
lsEat
+
wwEat;
//
委托链
eatChain(
"
西瓜
"
); Console.WriteLine(); Console.WriteLine(
"
李四出去接电话
"
); eatChain
-=
lsEat; eatChain(
"
香蕉
"
); Console.WriteLine(); Console.WriteLine(
"
李四回来了
"
); eatChain
+=
lsEat; eatChain(
"
橘子
"
); Console.WriteLine(); Console.WriteLine(
"
这是赵六来了
"
); eatChain
+=
delegate
(
string
food) { Console.WriteLine(
"
赵六吃:
"
+
food); };
//
匿名方法;
eatChain(
"
苹果
"
); Console.ReadKey(); } } }
输出结果:与一相同。
三、
View Code
using
System;
//
三、代理作为方法的参数示例
namespace
DelegateDemo {
delegate
void
EatDelegate(
string
food);
class
Man {
private
string
name;
public
Man(
string
name) {
this
.name
=
name; }
public
void
Eat(
string
food) { Console.WriteLine(name
+
"
吃:
"
+
food); } }
class
MyDelegate {
static
void
EatTogether(
string
food,
params
EatDelegate[] values)
//
代理作为方法的参数进行传递
{
if
(values
==
null
) { Console.WriteLine(
"
座谈会结束
"
); }
else
{ EatDelegate eatChain
=
null
;
foreach
(EatDelegate value
in
values) { eatChain
+=
value; } eatChain(food); } }
static
void
Main(
string
[] args) { Man zs
=
new
Man(
"
张三
"
); Man ls
=
new
Man(
"
李四
"
); Man ww
=
new
Man(
"
王五
"
); EatDelegate zsEat
=
new
EatDelegate(zs.Eat); EatDelegate lsEat
=
new
EatDelegate(ls.Eat); EatDelegate wwEat
=
new
EatDelegate(ww.Eat); Console.WriteLine(
"
张三、李四、王五开座谈会
"
); EatTogether(
"
西瓜
"
, zsEat, lsEat, wwEat); Console.WriteLine(); Console.WriteLine(
"
李四出去接电话
"
); EatTogether(
"
香蕉
"
, zsEat, wwEat); Console.WriteLine(); Console.WriteLine(
"
李四回来了
"
); EatTogether(
"
橘子
"
, zsEat, lsEat, wwEat); Console.WriteLine(); EatTogether(
null
,
null
); Console.ReadKey(); } } }
输出结果:
四、
View Code
using
System;
//
四、执行时传入方法的名称动态地决定欲调用的方法
namespace
DelegateDemo {
class
MyDelegate {
public
delegate
int
GenericFun(
int
a,
int
b);
public
static
int
Add(
int
a,
int
b) {
return
a
+
b; }
public
static
int
Sub(
int
a,
int
b) {
return
a
-
b; }
public
static
int
PrintResult(GenericFun action,
int
a,
int
b)
//
执行时传入方法的名称动态地决定欲调用的方法
{
int
result
=
action(a, b);
return
result; }
static
void
Main(
string
[] args) { Console.WriteLine(
"
3+4=
"
+
PrintResult(Add,
3
,
4
)); Console.WriteLine(
"
3-4=
"
+
PrintResult(Sub,
3
,
4
)); Console.ReadKey(); } } }
输出结果:
3+4=7
3-4=-1
五、
View Code
using
System;
//
五、最后一个例子
namespace
DelegateDemo {
delegate
int
MathOperationsDelegate(
int
value);
class
MathOperations {
public
static
int
MultiByTwo(
int
value) {
return
value
*
2
; }
public
static
int
Square(
int
value) {
return
value
*
value; } }
class
MyDelegate {
public
static
void
ProcessAndDisplayRusult(MathOperationsDelegate action,
int
value) {
int
result
=
action(value); Console.WriteLine(result); }
static
void
Main() { MathOperationsDelegate[] operations
=
{
new
MathOperationsDelegate(MathOperations.MultiByTwo),
new
MathOperationsDelegate(MathOperations.Square) };
for
(
int
i
=
0
; i
<
operations.Length; i
++
) { Console.WriteLine(
"
使用operation[{0}]
"
, i); ProcessAndDisplayRusult(operations[i],
3
); } Console.ReadKey(); } } }
输出结果:
使用operation[0]
6
使用operation[1]
9
<script type="text/javascript"></script>