c# 中的Delegate与Action(界面多线程应用)

很多C#初学者,都遇到过这样的问题,今天就这个问题,进行分析。

根源

先说下这个问题产生的根源,大家都知道,程序运行起来之后,首先会有一个主线程,主线程用于处理控件生成、界面渲染、事件响应等操作,因此我们可以理解为窗体里的控件是属于主线程的。

如果我们想实现与主线程同时执行另一件事,一般会去使用多线程,因此多线程,从某种意义上来说,它和主线程的身份是平等的,就像你和你的同事的关系一样,你们是平级的关系。如果你同事有一天想从你手上把你的项目程序拿过去,你愿不愿意?

所以,如果在多线程里操作主线程的控件,你觉得主线程会不会答应,当然不会,所以,它就会给你报个错,给你一个警告!

分析

那么如何解决呢?

所以你的同事就会找到你们领导,跟你们领导这样说:我手头上的这个100万的项目,能给公司带来50%的利润,现在需要用到他之前那个项目里的一个小知识,需要他把程序给我参考一下。

于是,领导和你“商量”了一下,你便妥协了。

你那个同事利用的招数叫做—————委托。

现在多线程要干这个事,也要靠委托来做。

委托

委托定义:委托(Delegate) 是对某个方法的引用的一种引用类型变量。

那就别看了,跟着我动手做。

1、声明委托

委托声明需要根据执行的方法来定,严格来说,就是根据执行方法的返回值和参数,我们只是给窗体的Text设置一个固定值而已,因此我们的参数是空,返回值也为空。

声明委托如下:

    //声明委托
    public delegate void SetFormTextDelegate();

2、创建委托对象

委托严格来说是一种类型,就像类一样,如果想要调用某个类,必须要创建一个该类的对象,所以我们要创建一个委托对象:

    //创建委托对象
    private SetFormTextDelegate SetFormText;

3、创建委托方法

委托对象也只是一个对象而已,就像领导一样,领导是不可能干活的,最终干活还得靠底下的兵来干,所以我们还得招人去干活。

招人干活就是委托方法,我们现在这个活很简单,所以我们的方法也很简单。

        //执行方法
        private void ExcuteMethod()
        {
            this.Text = "多线程测试";
        }

4、委托绑定

我们招到了一个“兵”,现在也有一个部门领导,怎么把他们联系起来呢?

很简单,让人事把这个兵分到这个部门就行了,这个分配的过程就是委托绑定,代码如下:

      //委托绑定
      this.SetFormText = ExcuteMethod;

5、委托调用

万事俱备,只欠东风,终于干活了。

作为公司的老板,一般是不可能跟员工打交道的,他会把任务分配给部门领导,部门领导会把活再分配下去,所以我们委托调用,也是调用委托对象。

        /// <summary>
        /// 多线程方法
        /// </summary>
        private void ThreadMethod()
        {
            //调用委托
            SetFormText();
        }

以上五步,就是委托的实现过程。

然而,我们运行之后,还是会报错。

没有那么简单的事!

因为想要在多线程里操作主线程的控件,你还得经过控件的同意,怎么经过控件同意呢?

控件的父类Control提供了一个这样的方法:

意思就是说,想要操作控件,必须要通过Invoke方法来实现,Invoke方法里参数是一个委托,于是,我们只能灰溜溜地,这样写:

果然,按照规矩来,就能达到效果:

简化

微软从某个版本开始,出来了Action和Lamda表达式,Action是系统委托,也就是说,不需要我们手动创建委托了,它有个兄弟叫Func,Action没有返回值,最多可以有16个参数,Func必须要有返回值,最多可以有16个参数,最后一个参数表示返回值。

于是我们开始简化:

第一步简化:用Action作为委托来创建

        /// <summary>
        /// 多线程方法
        /// </summary>
        private void ThreadMethod()
        {
            //创建委托、绑定委托
            Action action = new Action(ExcuteMethod);
            //调用委托
            this.Invoke(action);
        }
        
        //执行方法
        private void ExcuteMethod()
        {
            this.Text = "多线程测试";
        }

第二步简化:委托对象只用一次,所以可以直接放到参数里

        /// <summary>
        /// 多线程方法
        /// </summary>
        private void ThreadMethod()
        {
            //创建委托、绑定委托、调用委托
            this.Invoke(new Action(ExcuteMethod));
        }
        //执行方法
        private void ExcuteMethod()
        {
            this.Text = "多线程测试";
        }

第三步简化:用Lamda表达式代替方法

        /// <summary>
        /// 多线程方法
        /// </summary>
        private void ThreadMethod()
        {
            //创建委托、绑定委托、调用委托
            this.Invoke(new Action(()=>
            {
                this.Text = "多线程测试";
            }));
        }

总结

我们所以常写的那行代码,其实只是一种简写方式而已,委托的五步法,不管怎么简化,怎么优化,其实本质还是一样,都离开不了这五个步骤。

这就是经典。

文章来源于知乎,作者写的非常有条理,有浅及深

Delegate与Action,建议先看为敬 - 知乎 (zhihu.com)

  • 10
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值