委托的使用 - 浅谈

一,声明委托

  对于委托,定义它就是要告诉编译器,这种类型的委托表示哪种类型的方法.然后,必须创建该委托的一个或多个委托实例,编译器将在后台创建表示该委托的一个类.

  因为定义委托基本上是定义一个新类,所以可以在定义类的任何相同地方定义委托.

  在术语方面,和"类,对象"不同."类"表示的是较为广义的定义,"对象"表示类的实例.但是委托只有一个术语,在创建委托实例时,所创建的委托的实例仍然称为委托.

  如下显示委托的声明方式:

1
2
//声明委托.
private delegate string GetAString();

 

二,使用委托

  如下例子:

1 int x = 5;
2 //通过委托的方式.
3 GetAString stringMethod = new GetAString(x.ToString);
4 Console.WriteLine(stringMethod());  

  也可以使用委托推断,只需将地址传递给委托类型的变量(在后台,C#编译器会做同样的处理,即会在后台创建一个委托实例 "newGetAString(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委托实例封装的方法.

posted @ 2016-02-24 14:23  余先森  阅读(99)  评论(0编辑  收藏  举报