一,声明委托
对于委托,定义它就是要告诉编译器,这种类型的委托表示哪种类型的方法.然后,必须创建该委托的一个或多个委托实例,编译器将在后台创建表示该委托的一个类.
因为定义委托基本上是定义一个新类,所以可以在定义类的任何相同地方定义委托.
在 术语 方面,和"类,对象"不同."类"表示的是较为广义的定义,"对象"表示类的实例.但是委托只有一个术语,在创建委托实例时,所创建的 委托的实例 仍然称为 委托 .
如下显示委托的声明方式:
//声明委托.
private delegate string GetAString();
二,使用委托
如下例子:
1
int
x =
5
;
2
//
通过委托的方式.
3
GetAString stringMethod =
new
GetAString(x.ToString);
4
Console.WriteLine(stringMethod());
也可以使用 委托推断 ,只需将地址传递给委托类型的变量(在后台,C#编译器会做同样的处理,即会在后台创建一个委托实例 " new GetAString(x.ToString)"):
1
//
使用委托推断,只需将地址传递给委托实例.
2 GetAString secondMethod = x.ToString;
实际上,调用委托时,给委托实例提供圆括号与调用委托的Invoke()方法,是完全相同的:
1
Console.WriteLine(stringMethod());
//
委托方式1(使用圆括号的方式).
2
Console.WriteLine(stringMethod.Invoke());
//
委托方式2(使用调用Invoke()方法的方式).
原因是对于委托变量stringMethod,C#编译器会调用stringMethod.Invoke()代替stringMethod().
值得注意的是,在给一个委托类型的变量赋值的时候,方法的名称不能带有"()"括号,上述例子,调用 x.ToString()方法,会返回一个不能赋予委托变量的字符串对象(而不是方法的地址).
委托的一个特征是,它们是类型安全的,可以确定被调用的方法的签名是正确的.但是委托不关心在什么类型上调用改方法,甚至不考虑方法是静态的,还是实例方法.
如下例子演示了委托可以使用实例方法,也可以使用静态方法:
Currency结构的声明:
1
namespace
Wrox.ProCSharp.Delegates {
2
struct
Currency {
3
public
uint
Dollars;
4
public
ushort
Cents;
5
6
public
Currency(
uint
dollars,
ushort
cents) {
7
this
.Dollars =
dollars;
8
this
.Cents =
cents;
9
}
10
11
public
override
string
ToString() {
12
return
string
.Format(
"
${0}.{1,-2:00}
"
, Dollars, Cents);
13
}
14
15
public
static
string
GetCurrencyUnit() {
16
return
"
Dollar
"
;
17
}
18
19
public
static
explicit
operator
Currency(
float
value) {
20
checked
{
21
uint
dollars = (
uint
)value;
22
ushort
cents = (
ushort
)((value - dollars) *
100
);
23
return
new
Currency(dollars, cents);
24
}
25
}
26
27
public
static
implicit
operator
float
(Currency value) {
28
return
value.Dollars + (value.Cents /
100.0f
);
29
}
30
31
public
static
implicit
operator
Currency(
uint
value) {
32
return
new
Currency(value,
0
);
33
}
34
35
public
static
implicit
operator
uint
(Currency value) {
36
return
value.Dollars;
37
}
38
}
39
40
}
在住函数中调用:
1
using
System;
2
3
namespace
Wrox.ProCSharp.Delegates
4
{
5
class
Program
6
{
7
private
delegate
string
GetAString();
8
9
static
void
Main()
10
{
11
int
x =
40
;
12
GetAString firstStringMethod =
x.ToString;
13
Console.WriteLine(
"
String is {0}
"
, firstStringMethod());
14
15
Currency balance =
new
Currency(
34
,
50
);
16
17
//
firstStringMethod references an instance method
18
firstStringMethod =
balance.ToString;
19
Console.WriteLine(
"
String is {0}
"
, firstStringMethod());
20
21
//
firstStringMethod references a static method
22
firstStringMethod =
new
GetAString(Currency.GetCurrencyUnit);
23
Console.WriteLine(
"
String is {0}
"
, firstStringMethod());
24
25
}
26
}
27
}
输出:
String
is
40
String
is
$
34.50
String
is
Dollar
再来看一个委托使用:
定义操作的方法的类:
1
namespace
SimpleDelegates_Demo {
2
class
MathOperations {
3
public
static
double
MultiplyByTwo(
double
value) {
4
return
value *
2
;
5
}
6
7
public
static
double
Square(
double
value) {
8
return
value *
value;
9
}
10
}
11
12
}
在主函数中使用:
1
using
System;
2
3
namespace
SimpleDelegates_Demo {
4
delegate
double
Operate(
double
input);
5
class
Program {
6
static
void
Main(
string
[] args) {
7
Operate[] actions =
{ MathOperations.MultiplyByTwo, MathOperations.Square };
8
//
遍历每个委托实例.
9
foreach
(Operate action
in
actions) {
10
ProcessAndDisplayResult(action,
2
);
11
ProcessAndDisplayResult(action,
2.5
);
12
ProcessAndDisplayResult(action,
5.2
);
13
Console.WriteLine();
14
}
15
}
16
17
static
void
ProcessAndDisplayResult(Operate action,
double
inputVal) {
18
Console.WriteLine(
"
Input is [{0}],Result is [{1}]
"
, inputVal, action(inputVal));
19
}
20
}
21
}
output:
1
Input
is
[
2
],Result
is
[
4
]
2
Input
is
[
2.5
],Result
is
[
5
]
3
Input
is
[
5.2
],Result
is
[
10.4
]
4
5
Input
is
[
2
],Result
is
[
4
]
6
Input
is
[
2.5
],Result
is
[
6.25
]
7
Input
is
[
5.2
],Result
is
[
27.04
]
在这个例子中,我们将委托实例封装到一个数组中,然后遍历每个委托实例,然后传递遍历到特定的方法中调用,这说明使用委托的一种方式 - 即把方法组合到一个数组中来使用,这样就可以在循环中调用不同的方法了.
值得注意的是,这里 ProcessAndDisplayResult(Operate action, double inputVal) 不是多余的.
当我们在主函数的第10~12行中传递action委托实例到 ProcessAndDisplayResult(Operate action, double inputVal) 方法的时候,
action就是
委托表示的方法.
而在ProcessAndDisplayResult(Operate action, double inputVal)方法体中,也就是上面Program类中的第18行中的action(inputVal),或action(2)实际上调用这个方法,参数放在圆括号中.也就是说, action(inputVal),或action(2) 实际上是调用action委托实例封装的方法.

