c# 委托探究

什么时候使用委托呢?

1.程序中有的方法很耗时,而调用这个耗时方法返回的结果值,需要在接下来的代码中使用到,这时使用委托,将耗时方法与委托绑定(Func),在使用委托的异步调用BeginInvoke,程序代码接着处理其它项,需要时使用 Func.EndInvoke(AsyncResult)得到耗时方法的结果值

(除了这种需要使用返回值的情况,假设耗时方法去完成界面的一部分工作,而另一部分工作由其它代码块完成,使用委托的异步调用,二者并行执行,缩短程序执行时间)

2.async/await 与Task.Run() 结合使用,异步调用,并且界面上不会卡死(经测试第1种调用耗时方法时界面无法响应用户其它的操作),Task是线程池的升级版,使用Task.Run不一定会创建新线程,也可能在空闲的线程执行,查看Task.Run,如下图,也是结合委托来使用的

3.父子界面,父子控件 可以使用委托和事件, 还有常见的观察者模式(一对多),比如猫叫了,老鼠跑了 主人醒了

 

 上面两种具体的使用参考:

一.委托类别

1)delegate

delegate至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型

例:public delegate int MethodtDelegate(int x, int y);表示有两个参数,并返回int型

上述委托绑定的方法也必须是返回类型为int,参数为int,且为2个

2)Action Action是无返回值的泛型委托。

Action 表示无参,无返回值的委托

Action<int> 表示有传入参数int;无返回值的委托

Action<int,string> 表示有传入参数int,string ;无返回值的委托

......

3)Func

Func是有返回值的泛型委托

Func<int> 表示无参,返回值为int的委托

Func<int,string>表示传入参数为int类型,返回值为string类型

.......

 Func至少0个参数,至多16个参数,根据返回值泛型返回。必须有返回值,不可void


二、委托调用

1.同步调用

Invoke

2.异步调用

BeginInvoke,

BeginInvoke 方法参数不定,但是最后两个参数固定,其中倒数第2个参数,到时第1个参数为必须,若没有,传入null,
倒数第2个参数表示回调函数,倒数第1个参数表示传给回调函数的参数内容

三、调用例子代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class frmWeiTuo : Form
    {
        public frmWeiTuo()
        {
            InitializeComponent();
        }

        public delegate string testEventHander(string arg);
      


        private void btnAction_Click(object sender, EventArgs e)
        {
            this.richTextBox1.Text = "";
            //Action委托,Func 委托 作为方法的类型,
            //Test(msg, "huanggang");
            //Test(msg, 30);
           
            TestFunc(msgFunc,"shifang");
            TestFunc(msgFunc,31);


            //delegate 委托
            //将方法msgDelegate 与委托绑定,
            //testEventHander testEvent = new testEventHander(msgDelegate);
            //MessageBox.Show( msgDelegate("huanggang"));

        }
        /// <summary>
        ///   Action是无返回值的泛型委托 例如Action<int,string> 表示有传入参数int,string无返回值的委托
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action"></param>
        /// <param name="p"></param>
        public void Test<T>(Action<T> action, T p)
        {
            //action(p);

           // action.Invoke(p); //同步调用
            action.BeginInvoke(p,null,null); //异步调用
            this.richTextBox1.Text += "Test" + "\r\n";

        }
        /// <summary>
        ///  Func是有返回值的泛型委托
        /// T1为传入参数,T2为函数返回类型 比如Func(string,int) 表示传入参数是string类型,函数返回类型为int
        /// BeginInvoke  方法参数不定,但是最后两个参数固定,其中倒数第2个参数,到时第1个参数为必须,若没有,传入null,
        /// 倒数第2个参数表示回调函数,倒数第1个参数表示传给回调函数的参数内容
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="func"></param>
        /// <param name="arg"></param>
        public void TestFunc<T1,T2>(Func<T1,T2> func,T1 arg)
        {

          //  this.richTextBox1.Text += func(arg);

          //  this.richTextBox1.Text += func.Invoke(arg);//同步
        
            IAsyncResult asyncResult = func.BeginInvoke(arg, null, null);//异步调用,
            
           var result= func.EndInvoke(asyncResult); //接收委托返回的值
            this.richTextBox1.Text += result;
        }

        public void msg(string name)
        {
            // 当使用   action.BeginInvoke(p,null,null) 调用时,会报错,提示从不是当前的线程访问
     
             // this.richTextBox1.Text += name+"\r\n";

            //action.BeginInvoke(p,null,null) 调用 ,使用线程匿名委托 delegate (){} 匿名委托写法

            richTextBox1.BeginInvoke(new ThreadStart(delegate ()
                            {
                                richTextBox1.Text += name + "\r\n";
                            }));
            
        }
        public void msg(int age)
        {
            richTextBox1.BeginInvoke(new ThreadStart(delegate()
            {
                richTextBox1.Text += age + "\r\n";
            }));
          
        }
        public string msgFunc(string name)
        {
            //this.richTextBox1.Text += name + "\r\n";
            return name + "\r\n";
        }
        public int msgFunc(int age)
        {
            return age;
        }

        public string msgDelegate(string name)
        {
            //this.richTextBox1.Text += name + "\r\n";
            return name + "\r\n";
        }
        public int msgDelegate(int age)
        {
            return age;
        }

        private void btnAsync_Click(object sender, EventArgs e)
        {
            Action<string> ac = msg;
            ac("huanggang");

            //匿名函数的写法,Lambda写法 ,可以理解为委托类型的对象
            Action<string> ac1 = (t) => { msg(t); };

            Action<int> ac2 = (a) => { msg(a); };
            ac1.Invoke("石芳");
            ac2.Invoke(30);
            testEventHander testEvent = msgDelegate;
            testEvent("30");
        }
    }
}

 以上,若不有不对的,大家多批评指正,谢谢!

本文参考链接:

https://www.cnblogs.com/yaopengfei/p/8094512.html

https://www.cnblogs.com/mq0036/p/9166893.html

posted @ 2020-01-13 21:56  古道子  阅读(244)  评论(0编辑  收藏  举报