委托

一、委托案例引入

1.案例一:

首先新建一个控制台项目委托案例一,一个类库委托类库一,在类库一中的类Class1中编写Do()方法。然后在控制台项目委托类型一种输出,代码如下:

Class1中的代码:

 1 namespace 委托类库一
 2 {
 3     public class Class1
 4     {
 5         public void Do()
 6         {
 7             Console.WriteLine("======================================");
 8 
 9             Console.WriteLine("======================================");
10 
11             Console.WriteLine("======================================");
12 
13             Console.WriteLine("======================================");
14         }
15     }
16 }
View Code

委托类型一中的代码:

 1 namespace 委托案例一
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Class1 c = new Class1();
 8             c.Do();
 9 
10             Console.ReadKey();
11         }
12     }
13 }
View Code

输出结果显而易见。

现在我要在输出的结果(四条双等线)中间再输出当前时间,于是我在Class1中又增加一个方法,并且在Do()中调用,如下:

 1 namespace 委托类库一
 2 {
 3     public class Class1
 4     {
 5         public void Do()
 6         {
 7             Console.WriteLine("======================================");
 8 
 9             Console.WriteLine("======================================");
10 
11             GetCurrentDate();
12 
13             Console.WriteLine("======================================");
14 
15             Console.WriteLine("======================================");
16         }
17 
18         public void GetCurrentDate()
19         {
20             Console.WriteLine(DateTime.Now.ToString());
21         }
22     }
23 }
View Code

现在委托案例一中输出的结果如下:

======================================
======================================
2017/4/25 17:37:21
======================================
======================================

现在我想做一些改变,又新建一个项目,委托类型1,在这个控制台中我想把当前时间保存到文本文件中,这样,我就得改动Do()中调用的方法GetCurrentDate()的方法体,如果有N个控制台项目,都要调用委托类库一的Class1中的方法,并且每个控制台项目中,要求在双等线中间要做的操作不一样,那我就需要在Class1中写N个方法,并且切换一次控制台项目,就要改动Do()中调用的方法,这是一件很麻烦的事情。有其他方式解决吗?

如果在Do()方法中用一个变量代替GetCurrentDate()这个方法,我们在控制台项目中需要做什么操作,把需要的操作(方法)传给这个变量,那么问题就可以解决了。把方法传给一个变量,这就需要用到委托了。

如果我把Do()中的方法用一个委托变量代替,容易想到,我要创建的委托也应该放在当前类库中。所以在当前类库中添加一个类,改造成委托,然后在需要使用委托变量的Class1这个类中声明委托变量,在Do()方法中调用。代码如下:

1.定义委托类型:

1 namespace 委托类库一
2 {
3     public delegate void E1Delegate();//委托和抽象方法类似,只是关键字不同
4 }
View Code

2.在使用的类中声明委托变量,并且调用:

 1 namespace 委托类库一
 2 {
 3     public class Class1
 4     {
 5 
 6         public E1Delegate method;//成员变量,默认值是null
 7         public void Do()
 8         {
 9             Console.WriteLine("======================================");
10 
11             Console.WriteLine("======================================");
12 
13             //GetCurrentDate();
14 
15 
16             if(method!=null)
17             {
18                 method();//用委托变量调用
19             }
20 
21             
22 
23 
24             Console.WriteLine("======================================");
25 
26             Console.WriteLine("======================================");
27         }
28 
29         //public void GetCurrentDate()
30         //{
31         //    Console.WriteLine(DateTime.Now.ToString());
32         //}
33     }
34 }
View Code

3.在控制台程序中创建要绑定的方法,并且把方法赋值给委托变量:

 1 namespace 委托案例一
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Class1 c = new Class1();
 8             //c.Do();
 9             c.method = GetCurrentDate;//把方法赋值给委托变量的时候,方法不需要带括号
10             c.Do();
11 
12             Console.ReadKey();
13         }
14 
15         static void GetCurrentDate()
16         {
17             Console.WriteLine(DateTime.Now.ToString());
18         }
19     }
20 }
View Code

此时,在委托案例一这个项目就已经实现了本文开始的效果。在委托案例1控制台程序的代码如下:

 1 namespace 委托案例1
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Class1 c = new Class1();
 8             //c.Do();
 9             c.method = GetCurrentDate;//把方法赋值给委托变量的时候,方法不需要带括号
10             c.Do();
11 
12             Console.ReadKey();
13         }
14 
15         static void GetCurrentDate()
16         {
17             File.WriteAllText("datetime.txt",DateTime.Now.ToString());
18             Console.WriteLine("当前时间已经写入到了txt文件中");
19         }
20     }
21 }
View Code

委托案例一和委托案例1运行结果对比:

案例一:

======================================
======================================
2017/4/25 19:16:45
======================================
======================================

案例1;

======================================
======================================
当前时间已经写入到了txt文件中
======================================
======================================

以上就是委托的使用场景和过程。

当然,上面的委托使用过程还能进一步优化:

在使用委托变量的Class1这个类中,我们可以把成员变量,改成局部变量(Do()方法的参数)。然后在控制台程序中直接把方法作为参数通过Do()传递。代码如下:

Class1中:

 1 namespace 委托类库一
 2 {
 3     public class Class1
 4     {
 5 
 6         //public E1Delegate method;//成员变量,默认值是null
 7         public void Do(E1Delegate method)
 8         {
 9             Console.WriteLine("======================================");
10 
11             Console.WriteLine("======================================");
12 
13             //GetCurrentDate();
14 
15 
16             if(method!=null)
17             {
18                 method();//用委托变量调用
19             }
20 
21             
22 
23 
24             Console.WriteLine("======================================");
25 
26             Console.WriteLine("======================================");
27         }
28 
29         //public void GetCurrentDate()
30         //{
31         //    Console.WriteLine(DateTime.Now.ToString());
32         //}
33     }
34 }
View Code

控制台程序:

 1 namespace 委托案例一
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Class1 c = new Class1();
 8             //c.Do();
 9             //c.method = GetCurrentDate;//把方法赋值给委托变量的时候,方法不需要带括号
10             c.Do(GetCurrentDate);
11 
12             Console.ReadKey();
13         }
14 
15         static void GetCurrentDate()
16         {
17             Console.WriteLine(DateTime.Now.ToString());
18         }
19     }
20 }
View Code

留个练习:

给个指定的数组,不同的调用者给每个数组中的元素添加的前后缀不同,用委托实现。

二、案例二:简单模拟两个窗口聊天

如图:我在左边的窗口的发送的消息文本框中,输入发送的消息,然后点击发送消息,弹出新窗口,并且同步显示刚才发送的消息。接下来在右边的回复消息文本框中,输入回复消息,点击回复后,左边的窗口中的未读消息中马上显示刚才回复的消息,同时右边的窗口关闭。

这个功能有很多实现方式,这里我们之关注如何用委托实现。

分析:

1.在未读消息中显示右边窗口(FrmPostBackMsg)回复的消息,最终是要把消息内容在未读消息的文本框中显示出来,所以最终会执行给未读的文本框赋值的代码,并且只能在左边的窗口(FrmSendMsg)文件中,才能给未读消息的文本框赋值。所以需要在左边的窗口文件中设计一个方法(UpdateText(string s))实现这个赋值功能。

2.我们需要在右边的窗口关闭时候,把回复消息同步到左边的窗口中,也就是说,我们在点击回复的时候,需要调用左边窗口中的赋值方法,可是这个方法在别处,不能直接调用,有什么办法可以调用呢?这时候,我们想到了委托,用一个委托变量把它装起来,带到右边的窗口中就行。

3.那我们在哪声明委托变量,在哪装方法,在哪取方法呢?因为方法在左边的窗口中,所以肯定需要在左边的窗口中装方法,装好后传到右边的窗口中,所以在弹出右边的窗口的时候,需要传入这个方法,然后在右边的窗口的构造函数中取到方法(构造函数的一个参数是委托,用来接收传过来的方法),然后在点击回复的时候,调用这个委托变量。当然,如果要使用这个委托变量,必须把它提升为全局变量。代码如下:

左边的窗口:

 1  public partial class FrmSendMsg : Form
 2     {
 3         public FrmSendMsg()
 4         {
 5             InitializeComponent();
 6         }
 7 
 8         private void btnSendMsg_Click(object sender, EventArgs e)
 9         {
10             FrmPostBackMsg postBackMsg = new FrmPostBackMsg(txtMsg.Text.Trim(),UpdateText);
11             postBackMsg.Show();
12         }
13 
14         private void UpdateText(string s)
15         {
16             this.txtReceiveMsg.Text = s;
17         }
18     }
View Code

右边的窗口:

 1  public partial class FrmPostBackMsg : Form
 2     {
 3         DelegatePostBackMsg _delegateMsg;
 4         public FrmPostBackMsg()
 5         {
 6             InitializeComponent();
 7         }
 8 
 9         public FrmPostBackMsg(string msg, DelegatePostBackMsg delegateMsg) :this()
10         {
11             txtMsg.Text = msg;
12             this._delegateMsg = delegateMsg;
13         }
14 
15         private void btnPostBack_Click(object sender, EventArgs e)
16         {
17             if (_delegateMsg!=null)
18             {
19                 _delegateMsg(txtPostBackMsg.Text.Trim());
20             }
21 
22             this.Close();
23         }
24     }
View Code

 三、委托的实质

委托实质上是一个类,它继承于它继承自MulticastDelegate,Delegate是所有委托的祖宗类。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             #region MyRegion
 6 
 7             //DelegateM1 m1 = M1;
 8             ////反编译后等价于 DelegateM1 m1 = new DelegateM1(M1);就是说委托变量只能接受委托对象,我们把方法赋值给委托,其实内部是把方法作为委托的参数传了进去
 9 
10             //m1();//调用委托的时候,写成方法的形式,实际上是调用委托的 m1.Invoke();方法
11 
12             //委托实际上是一个类,它继承自MulticastDelegate,MulticastDelegate又继承自Delegate(所有的委托都继承与它)
13 
14             #endregion
15 
16             DelegateM2 m2 = new DelegateM2(M2);
17             int res= m2(1,2);
18             Console.WriteLine(res);
19 
20             Console.ReadKey();
21         }
22 
23         static void M1()
24         {
25             Console.WriteLine("这是方法M1");
26         }
27 
28         static int M2(int n1,int n2)
29         {
30             return n1 + n2;
31         }
32     }
33 
34     public delegate void DelegateM1();
35 
36     public delegate int DelegateM2(int n1,int n2);
View Code
原文地址:https://www.cnblogs.com/wesley168/p/6763861.html