[转载]C# 委托知识总结

[转载]C# 委托知识总结 – 情缘 – 博客园.

1.什么是委托,为什么要使用委托

我正在埋头苦写程序,突然想喝水,但是又不想自己去掉杯水而打断自己的思路,于是 我就想让女朋友去给我倒水。她去给我倒水,首先我得让她知道我想让她干什么,通知她之后我可以继续写自己的程序,而倒水的工作就交给了她。这样的过程就相 当于一个委托。

在 程序过程中,当程序正在处理某个事件的时候,我需要另外的程序代码去辅助处理一些事情,于是委托另一个程序模块去处理,而委托就可以达到这种目的,我可以 利用委托通知另外的程序模块,该去调用哪个函数方法。委托其实就起到了这样一个作用,将函数签名传递到了另一个函数中。或许这样讲还是有些模糊,看看后面 的具体实例。

2.委托的定义

delegate int Add(int num1,int num2);

delegate void
ConvertNum(string result);


上面是定义两个委托的例子,其实很简单。声明一个委托使用delegate关键字,上面分别是定义的带返回值的委托和不带返回值的委托,

两个委托都有传递参数,当然也可以不传递参数。
其实委托也是一个类,委托派生为System.MulticastDelegate,而System.MulticastDelegate

又继承System.Delegate,如果你
知道这个也就明白委托其实是一个特殊的类。

委托的简单实用例子

1 public delegate string TeaDelegate(string spText);
2
3 public class DelegateSource
4 {
5 public void TestDelegate()
6 {
7 Operator op = new Operator();
8 TeaDelegate tea = new TeaDelegate(op.GetTea);
9 Console.WriteLine(去给我倒杯水);
10 Console.WriteLine();
11 string result=tea(去给我倒杯水);
12 Thread.Sleep(5000);
13 Console.WriteLine(result);
14 Console.WriteLine();
15 }
16 }
17
18 public class Operator
19 {
20 /// <summary>
21 /// 确定是否还有水
22 /// </summary>
23 private bool flag = true;
24
25 public string GetTea(string spText)
26 {
27 if (spText == 去给我倒杯水)
28 {
29 if (flag)
30 {
31 return 老公,茶来了;
32 }
33 else
34 {
35 return 老公,没有水了;
36 }
37 }
38 return 等待…….;
39 }
40 }

输出结果


上面使用最普通的一种方式来定义了一个委托的使用,这个例子虽然很简单,但是能够很形象的描述委托的使用。

3. 委托的三种形式


(1).推断

推断委托例子

1 public delegate string TeaDelegate(string spText);
2
3 public class DelegateSource
4 {
5 public void TestDelegate()
6 {
7 Operator op = new Operator();
8 TeaDelegate tea = op.GetTea;
9 Console.WriteLine(去给我倒杯水);
10 Console.WriteLine();
11 string result=tea(去给我倒杯水);
12 Thread.Sleep(5000);
13 Console.WriteLine(result);
14 Console.WriteLine();
15 }
16 }
17
18 public class Operator
19 {
20 /// <summary>
21 /// 确定是否还有水
22 /// </summary>
23 private bool flag = true;
24
25 public string GetTea(string spText)
26 {
27 if (spText == 去给我倒杯水)
28 {
29 if (flag)
30 {
31 return 老公,茶来了;
32 }
33 else
34 {
35 return 老公,没有水了;
36 }
37 }
38 return 等待…….;
39 }
40 }

在委托定义的例子中我们看到委托的使用方法是在委 托实例化的时候指定的[new DelegateName(FunctionName)],这里可能表述不是太但是代码应该看得白了。 而委托的推断,并没有new 委托这个步骤,而是直接将Function 指定给委托。

(2).匿名函数

匿名委托例子

1 public delegate string TeaDelegate(string spText);
2
3 public class DelegateSource
4 {
5 public void TestDelegate()
6 {
7 Operator op = new Operator();
8 bool flag = true;
9 TeaDelegate tea = delegate(string spText)
10 {
11 if (spText == 去给我倒杯水)
12 {
13 if (flag)
14 {
15 return 老公,茶来了;
16 }
17 else
18 {
19 return 老公,没有水了;
20 }
21 }
22 return 等待…….;
23 };
24
25 Console.WriteLine(去给我倒杯水);
26 Console.WriteLine();
27 string result=tea(去给我倒杯水);
28 Thread.Sleep(5000);
29 Console.WriteLine(result);
30 Console.WriteLine();
31 }
32 }


至于匿名委托,给人的感觉更为直接了,都不用显示的指定方法名,因为根本没有方法,而是指定的匿名方法。匿名方法在.NET 中提高了

代码的可读性和优雅性。对于更多操作较少的方法
直接写为匿名函数,这样会大大提高代码的可读性。这里有两个值得注意的地方: 第一,不能使用

跳转语句跳转到该匿名方法外,第二
不能使用ref,out修饰的参数

(3).多播委托

多播委托例子

1 public delegate string TeaDelegate(string spText);
2
3 public class DelegateSource
4 {
5 public void TestDelegate()
6 {
7 Operator op = new Operator();
8
9 TeaDelegate tea1 = op.GetTea;
10 TeaDelegate tea2 = op.Speak;
11 TeaDelegate tea = tea1 + tea2;
12
13 Console.WriteLine(去给我倒杯水);
14 Console.WriteLine();
15 string result=tea(去给我倒杯水);
16 Thread.Sleep(5000);
17 Console.WriteLine(result);
18 Console.WriteLine();
19 }
20 }
21
22 public class Operator
23 {
24 /// <summary>
25 /// 确定是否还有水
26 /// </summary>
27 private bool flag = true;
28
29 public string GetTea(string spText)
30 {
31 if (spText == 去给我倒杯水)
32 {
33 if (flag)
34 {
35 return 老公,茶来了;
36 }
37 else
38 {
39 return 老公,没有水了;
40 }
41 }
42 return 等待…….;
43 }
44
45
46 public string Speak(string spText)
47 {
48 Console.WriteLine(\n去把我的设计图稿拿来);
49 return null;
50 }
51 }


还是上面的那个实例,我不尽想让女朋友去给我掉杯水,还让她帮我将程序设计图稿拿过来。这个时候做的就不是一件事了,而是多件。

程序中也有很多这种情况,于是我们需要多播委
托,在一个委托上指定多个执行方法,这是在程序中可以行的。上面提到了,委托直接继承于

System.MulticastDelegate,
正是因为这个类可以实现多播委托。
如果调用多播委托,就可以按顺序连续调用多个方法。为此,委托的签名就必须返回void;否则,就只能得 到委托调用的最后一个方法的结果。所以在上面的这段代码中是得不到结果的

4.事件

使用C#编程,无论是 WinForm,WebForm 给人很难忘得就是它的控件,而他们的控件库使用方式都是使用使用事件驱动模式,而事件驱动模式却少不了委托。话不多说,看代码能够更清好的理解事件和委托 之间的联系.

事件的使用

1 public delegate void MyDelegate(string name);
2
3 public class EventSource
4 {
5 public event MyDelegate Event_Delegate;
6
7 public void SetCustomer(string name)
8 {
9 Console.WriteLine(事件发 生…..\n);
10 Console.WriteLine(hi! +name);
11 }
12
13 public void TestEvent()
14 {
15 EventSource source = new EventSource();
16 Console.WriteLine(订阅事件…..\n);
17 source.Event_Delegate += new MyDelegate(source.SetCustomer);
18 Console.WriteLine(触发事 件…..\n);
19 source.Event_Delegate(hechen);
20 Console.WriteLine(………………);
21 }
22 }


上面的代码中我们定义了一个委托,然后定义了一个类EventSource,这个类中声明了一个事件。定义一个事件使用event 关键字,定义一

个event必须指定这个event传递消息的委托,在触发事件之前必需订阅事件,我们使用+=
new 语法来订阅一个事件,也就相当于实例化一个事件。

当我们触发事件的时候,就会调用相应的方法去处理。

5. 泛型委托


委托是类型安全的引用,泛型委托就和我们常用的泛型类一样,这个类在使用的时候才能确定类型.通过泛型委托,我们可以在委托传递参数

之后知道它的类型.在.NET中有一个很典型的
泛型委托:

public delegate voie EventHandler<TEventArgs>(object
sender,TEventArgs e) where TEventArgs:EventArgs.

这是一个非常有特色的泛型委托,可能我们用的比较
少,但是作用是不能忽视的。
我们看看三个非常具有代表性的泛型委托.现在.NET4.0已经出来了,但是泛型委托.NET2.0就出来了,Linq 大家用的那叫一个甜,

为啥
函数式编程风格,匿名方法,Lamda表达式表达式使用是如此的魅力。但是大家仔细观察过没有,Linq 中的方法有几个经常出现的参数:

Action<T>,Predicate<T>,Func<T,
Result>

Func<T, E>:封装一个具有一个参数并返回 E 参数指定的类型值的方法,T 是这个委托封装方法的参数类型,E是方法的返回值类型。当然Func<T, Result> 只是其中的一种情况,这个委托还有其他的几种情况:Func<T> 这个是方法没有参数,返回值类型是T;Func<T1,T2,Result> 这个方法有两个参数,类型分别为T1,T2,返回值是Result,还有 Func<T1,T2,T3,Result>,Func<T1,T2,T3,T4,Result> 这几中情况,具体情况就不介绍了.我们还可以通过扩展类型,扩展为更多的参数.

Func 委托的使用

1 public void TestFunc()
2 {
3 TEventSource eventSource=new TEventSource();
4 Func<string, string> func = eventSource.GetTea;
5 string result = func();
6 Console.WriteLine(result);
7 }
8
9 public string GetTea(string context)
10 {
11 if (context == )
12 {
13 return 茶来了;
14 }
15 else
16 {
17 return 设计稿子来了;
18 }
19 }


Action<T>:封装一个方法,该方法只采用一个参数并且不返回值,包括
Action<T>,Action<T1,T2>,Action<T1,T2,T3>,Action<T1,T2,T3,T4>
几种情况,也可以
通过扩展方法去扩展参数的个数

Action 委托使用例子

1 public void TestAction()
2 {
3 TEventSource eventSource = new TEventSource();
4 Action<string> action = eventSource.Speak;
5 action(Action<T> 泛型委托);
6 }
7
8 public void Speak(string context)
9 {
10 Console.WriteLine(context);
11 }


Predicate<T>:表示定义一组条件并确定指定对象是否符合这些条件的方法。该委托返回的是一个bool类型的值,如果比较满足条件

返回true,否则返回false.其实上面的
Func 委托可以包含这个委托.不过这个委托和上面的两个不一样,它只有一种类型

Predicate 委托使用例子

1 public void TestPredicate()
2 {
3 TEventSource eventSource = new TEventSource();
4 Predicate<int> predicate = eventSource.IsRigth;
5 Console.WriteLine(predicate(0));
6 }
7
8 public bool IsRigth(int value)
9 {
10 if (value == 0)
11 {
12 return true;
13 }
14 else
15 {
16 return false;
17 }
18 }

6. 异步委托

投 票技术: 委托其实相当于一个线程,使用投票技术是使用异步委托的一种实现方式.Delegate类提供了方法BeginInvoke(),可以传送委托类型定义的 输入参数,其返回类型为IAsyncResult。IAsyncResult的IsCompleted属性可以判断委托任务是否完成

异步委托投票技术

1 public delegate int DelegateVote(int data, int ms);
2 /// <summary>
3 /// 使用投票操作完成委托任务
4 /// </summary>
5 public class VoteDelegate
6 {
7 /// <summary>
8 /// 休眠特定时间执行操作
9 /// </summary>
10 /// <param name=”data”></param>
11 /// <param name=”ms”></param>
12 /// <returns></returns>
13 public static int TakeWork(int data, int ms)
14 {
15 Console.WriteLine(开始调用TakeWork方法);
16 Thread.Sleep(ms);
17 Console.WriteLine(结束调用 TakeWork方法);
18 return data + 10;
19 }
20
21 public void TestDelegate()
22 {
23 DelegateVote voteDel = TakeWork;
24 IAsyncResult result = voteDel.BeginInvoke(1,5000,null,null);
25 while (result.IsCompleted == false)
26 {
27 Console.WriteLine(等待……);
28 Thread.Sleep(500);
29 }
30 int value = voteDel.EndInvoke(result);
31 Console.WriteLine(委托调用结果: +value);
32 }
33 }

等待句柄:等待句柄是使用 AsyncWaitHandle属性访问,返回一个WaitHandle类型的对象,它可以等待委托线程完成其任务。在这个参数中可以设置最大的等待时 间。

异步委托等待句柄

1 public delegate string WaitDelegate(string content);
2
3 public class WaitHandlerDelegate
4 {
5 public void TestWaitHander()
6 {
7 WaitDelegate del = GetTea;
8 IAsyncResult ar = del.BeginInvoke(hechen, null, null);
9 while (true)
10 {
11 Console.Write(.);
12 if (ar.AsyncWaitHandle.WaitOne(50, false))
13 {
14 break;
15 }
16 }
17 string result=del.EndInvoke(ar);
18 Console.WriteLine(result);
19
20 }
21
22 public static string GetTea(string content)
23 {
24 return 茶来了 +content;
25 }
26 }

异步回调:这个方式和投票技术 有点类似,不过在投票方式中BeginInvoke()方法第三个参数指定了一个方法签名,而这个方法参数接收IAsyncResult 类型的参数。

异步委托回调函数

1 public delegate string AsyDelegate(string content);
2
3 public class AsyncresultDelegate
4 {
5 public void TestAsync()
6 {
7 AsyDelegate del = GetTea;
8 del.BeginInvoke(hechen, delegate(IAsyncResult ar) {
9 Thread.Sleep(5000);
10 string result = del.EndInvoke(ar);
11 Console.WriteLine(result);
12 }, null);
13 for (int i = 0; i < 100; i++)
14 {
15 Console.WriteLine(等待…..);
16 Thread.Sleep(1000);
17 }
18 }
19
20 public static string GetTea(string content)
21 {
22 return 茶来了 + content;
23 }
24 }
赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏