• 委托


    一、委托案例引入

    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
  • 相关阅读:
    iOS10 的适配问题,你遇到了吗?导航栏标题和返回按钮神奇的消失了
    如何在获取不到第一响应者控件时移除键盘
    类名与字符串的互转
    clang format 官方文档自定义参数介绍(中英文)
    clang format 自定义样式常用参数说明
    Xcode 设置代码不自动换行
    企业项目如何打包成.ipa文件
    多个过渡动画效果
    压栈过渡动画
    底部不规则导航栏2
  • 原文地址:https://www.cnblogs.com/wesley168/p/6763861.html
Copyright © 2020-2023  润新知