zoukankan      html  css  js  c++  java
  • C#的委托Delegate

    一、委托基础

      1.什么是委托

      委托(Delegate) 是存有对某个方法的引用的一种引用类型变量,用关键字delegate申明,实现相同返回值和参数的函数的动态调用,提供了对方法的抽象。

      委托(Delegate)特别用于实现事件回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。

      2.声明委托

      委托声明后决定了该委托可以引用的方法。

       public delegate string MyDelegate(int i);

      上面声明的委托可以用于引用任何返回值为string类型并且参数为一个int类型的任意方法名的方法,例如下面这个:

      public static string GetStr(int i){return i.ToString();}

      所以委托的声明格式为:访问修饰符+delegate+返回类型+类型名+参数。

      3.初始化委托变量以及赋值

      声明了委托类型后,和string、int等类型一样需要声明变量才能使用。对于初始化变量的赋值有两种方式:

      (1)new实例化赋值

      和一般的类实例化一样,在构造函数中传入方法名即可。

      MyDelegate mydelegate = new MyDelegate(GetStr);

      (2)直接赋值

      由于方法名称和相应的委托之间存在隐身转换,所以可以等于号赋值。

      MyDelegate mydelegate = GetStr;

      以上例子都是直接将方法名赋值给委托变量的,这是因为方法由static修饰。对于非静态的变量还是需要实例化使用,如下:

      MyDelegate mydelegate = new People().GetStr;

      由于委托是引用类型,用 '=' 重新赋值后会改变方法的引用地址,下述例子也继续使用静态方法。

      4.多播委托

      委托对象可以通过 ‘+’ 运算法进行组合,一个合并委托调用所组合的委托的所有指向方法引用地址,合并的委托必须是相同类型的。不仅是对象可以组合,通过 '+' 运算符可以让委托变量对方法自增。

      (1)委托对象组合

      MyDelegate mydelegate1 = GetStr;
      MyDelegate mydelegate2 = GetStr;
      MyDelegate mydelegate3 = mydelegate1 + mydelegate2;

      (2)自增

      MyDelegate mydelegate = GetStr;
      mydelegate += GetStr;

      有增自然有减,可以通过 ‘-’ 运算符进行方法引用地址的剔除,如果有多个同样的方法,只删除其中一个。

      5.匿名方法

      我们之前的方法都是事先声明好了的,然后使用方法名。但是有时候我们不想要声明新方法,因为这个是一个临时的方法。那么就可以用在c# 2.0版本引入的匿名方法,或者是3.0以后版本的lambda表达式。

      匿名方法使用的也是delegate关键字,不需要定义返回类型,格式为: delegate (传入参数) {执行语句},如下:

      MyDelegate mydelegate = delegate(int i) { return i.ToString(); };

       lambda表达式简化了匿名方法的书写,去掉了delegate关键字并加入 '=>' 运算符:

      MyDelegate mydelegate = (int i) => { Console.WriteLine(i.ToString()); };

      6.委托调用

      委托的调用和方法的调用差不多,因为委托声明的时候参数和返回值都已经确定了,所有加入委托调用列表的方法都是一样的,所以当委托调用的时候所有方法会依次执行。多播委托的情况下会返回最后一个有返回值的方法结果。但是要注意委托变量是否为空,空的执行会报错。

      if(mydelegate != null)
          mydelegate(1);

      7.泛型委托 

      泛型委托的加入使委托的使用更加方便,简化我们的代码。常用的泛型委托有两种:Action和Func,他们的使用和一般的委托差不多,帮我们省去了声明的哪一步。

      Action是无返回值的委托,封装了从无参数到16个参数的委托。

      Action action1 = () => { Console.WriteLine("无参的情况"); };
      Action
    <int> action = (int i) => { Console.WriteLine(i.ToString()); };
      action
    += (int i) => { Console.WriteLine((i+1).ToString()); }; if (action != null)   action(1);

      Func是有返回参数,所以格式是Fun<T t1,.....,TResult result>,这个返回类型为最后一个参数,并且是必须的,传入参数类型可以没有,但是返回类型必须要。

        Func<string,string> func = (string str) => { return str; };
        if(func != null)
            Console.WriteLine(func("hahaha"));    

    二、委托的应用

      委托的声明和使用其实不难,但是很大的一个困扰就是不知道什么时候使用,园中有很多委托的文章我看了很多,大家都举了很多的例子,比如烧开水啥的,但是我觉得还是用实际的例子来说明比较好。可能很多人在工作了几年后都没有用过委托。所以,实践出真知。只有当真正用到的时候才能明白其中的含义。

      这里举在窗体程序中的跨窗体调用方法的例子。现在有两个窗体Form1和Form2,分别由一个文本框和一个按钮。现在通过Form1中的按钮打开Form2窗体,然后通过Form2窗体中的按钮点击更新Form1中文本框的内容。

      Form1窗体的代码如下:

        private void OpenBtn_Click(object sender, EventArgs e)
        {
            Form2 form2 = new Form2();
            form2.action = this.ModifyName;
            form2.Show();
        }
        private void ModifyName(string name)
        {
            NameTxt.Text = name;
        }  

      Form2窗体的代码如下:

        public Action<string> action;
        private void ModifyBtn_Click(object sender, EventArgs e)
        {
            ConfirmModify(action);
        }
        private void ConfirmModify(Action<string> action)
        {
            //省略数据库修改等操作.......
            if (action != null)
              action(ModifyTxt.Text);
        }   

       代码非常简单,Form1和Form2中的方法都是私有的,只通过Form2中的委托对象来执行Form1中的私有方法。虽然还有别的方法可以实现这个功能,但是我觉得这个方案是比较好的。

    三、总结

      有问题可以留言讨论,希望可以给大家带来帮助,共勉!

  • 相关阅读:
    centos7 使用docker 一键部署服务器
    node 连接mysql失败
    面试必会---模块化
    es6异步解决方案
    centos7 apache后台转nginx后台
    React + Ts 实现三子棋小游戏
    让你的项目使用Ts吧
    ES6 入门系列 ArrayBuffer
    怎么把使用vuepress搭建的博客部署到Github Pages
    Navicat Premium 15安装教程(完整激活版)
  • 原文地址:https://www.cnblogs.com/xwc1996/p/10268725.html
Copyright © 2011-2022 走看看