C# 委托&线程的见解(上)—— 委托

目录

委托相关

第一步:创建委托

第二步:定义委托API

第三步:调用委托

第四步:其他窗体实现委托

补充

控件创建委托

创建异步委托

Thread调用Control的Invoke

Thread调用Control的BeginInvoke

拓展


委托相关

        对于委托,我们都知道他是一个引用类型,具有引用类型所具有的通性。需要知道的是它保存的不是实际值,只是是保存对存储在托管堆中的对象的引用。或说的直接点,委托就相当于叫人帮忙,让它帮你做一些事情。我这里就举一些委托操作的小实例,来简单的说一下。

        在开始举例之前,再说一下,委托一般包含三个方法,分别是BeginInvoke、EndInvoke、Invoke。EndInvoke就不必说了,一看就知道是干嘛的。Invoke 和BeginInvoke,前一个是同步委托,后一个是异步委托,何为同步,何为异步呢?其实也可从字面意思理解,同步就是同时进行的,不能说你先执行,我后执行,那么异步就是与同步相对的,但是也不全相对,因为异步的执行不受主进程的影响,执行全看它个人了。

        这里所说的委托都是自己新建的委托,但还有种委托,是C#控件自带的委托,也分有同步异步之分,控件委托用处很大,在后面说线程的时候会说到,因为在使用线程时,有时控件委托是必要的。

        下面先单独说一个委托的例子吧:

第一步:创建委托

    //创建委托
    [Serializable, ComVisible(true)]//可省略
    public delegate void testDelegate(object sender, EventArgs e);

第二步:定义委托API

public class DelegateApi
{
    //定义委托API
    public static event testDelegate TestClick;

    //委托实现方法
    public static void OnTest(object sender, EventArgs e)
    {
        testDelegate handler = TestClick;
        if (handler != null)
           handler(sender, e);
    }
}

第三步:调用委托

//同类调用委托API
OnTest(sender, e);

//非同类调用委托API
DelegateApi.OnTest(sender, e);

第四步:其他窗体实现委托

private void Form1_Load(object serder, EventArgs e)
{
    //实例化API方法调用
    DelegateApi.TestClick += Form1_TestClick;
}

private void Form1_TestClick(object sender, EventArgs e)
{
    MessageBox.Show("委托调用");
}

       这是委托最常用也是很实用的一个例子,我们可以通过这种方式,实现不同窗体之间的交互,比如在A窗体调用委托API,在B窗口实例化API方法,这样就能达到在A窗口控制B窗口方法的执行。那么你可能就会问,我想传参数怎么办,其实很简单,委托API的传参与普通方法的传参类似,只需要在定义委托和API时这样定义:

补充

这里的handler其实类似于 handler.Invoke();,也就是同步委托,调用即执行。那么异步委托只需要写成handler.BeginInvoke(null, null);,这是没有回调函数的异步委托,当然想要调用回调函数,只需如下编写:

控件创建委托

Control的Invoke和BeginInvoke都执行在主线程即UI线程上

创建异步委托

private delegate void BeginInvokeDelegate();
private void BeginInvokeMethod(){
   //C代码段
}
private void butBeginInvoke_Click(object sender, EventArgs e) {
   //A代码段.......
   this.BeginInvoke(new BeginInvokeDelegate(BeginInvokeMethod));
   //B代码段......
}

(1)A在UI线程上执行完后,开始BeginInvoke,BeginInvoke是异步
(2)InvokeMethod方法,即代码段C不会执行,而是立即在UI线程上执行代码段B。
(3)代码段B执行完后(就是说butBeginInvoke_Click方法执行完后),InvokeMethod方法,即代码段C才在UI线程上继续执行。

Thread调用Control的Invoke

private Thread invokeThread;
private delegate void invokeDelegate();
private void StartMethod(){
   //C代码段......
   Control.Invoke(new invokeDelegate(invokeMethod));
  //D代码段......
}
private void invokeMethod(){
  //E代码段
}
private void butInvoke_Click(object sender, EventArgs e) {
   //A代码段.......
   invokeThread = new Thread(new ThreadStart(StartMethod));
   invokeThread.Start();
   //B代码段......
}

1. UI执行A
2. UI开线程InvokeThread,B和C同时执行,B执行在线程UI上,C执行在线程invokeThread上。
3. invokeThread封送消息给UI,然后自己等待,UI处理完消息后,处理invokeThread封送的消息,即代码段E
4. UI执行完E后,转到线程invokeThread上,invokeThread线程执行代码段D

Thread调用Control的BeginInvoke

private Thread beginInvokeThread;
private delegate void beginInvokeDelegate();
private void StartMethod(){
   //C代码段......
   Control.BeginInvoke(new beginInvokeDelegate(beginInvokeMethod));
  //D代码段......
}
private void beginInvokeMethod(){
  //E代码段
}
private void butBeginInvoke_Click(object sender, EventArgs e) {
   //A代码段.......
   beginInvokeThread = new Thread(new ThreadStart(StartMethod));
   beginInvokeThread .Start();
   //B代码段......
}

1. UI执行A
2. UI开线程beginInvokeThread,B和C同时执行,B执行在线程UI上,C执行在线程beginInvokeThread上。
3. beginInvokeThread封送消息给UI,然后自己继续执行代码D,UI处理完消息后,处理invokeThread封送的消息,即代码段E

拓展

委托实现异步线程,也可理解为非UI异步线程,为啥要我要说可以理解为非UI异步线程呢,因为它的委托创建与UI没有直接关系

        #region 非UI异步线程
        private object _args;
        public delegate void RunHandler(object args);//事件处理委托
        private event RunHandler Runs;//委托事件
        private event RunHandler CallBackFun;//委托事件
        public delegate void CallBackDelegate(RunHandler handler, object args);
        CallBackDelegate _d = TakesAWhile;

        /// <summary>
        /// 执行入口
        /// </summary>
        /// <param name="run"></param>
        /// <param name="callBackFun"></param>
        /// <param name="args"></param>
        public void DoProcess(RunHandler run, RunHandler callBackFun, object args)
        {
            Runs = run;
            _args = args;
            CallBackFun = callBackFun;
            //创建有回调函数的异步线程
            _d.BeginInvoke(Runs, _args, CallBack, _d);
            //创建无回调函数的异步线程
            //_d.BeginInvoke(Run, _args, null, null); 
        }

        /// <summary>
        /// 定义委托引用的方法
        /// </summary>
        /// <param name="handler"></param>
        /// <param name="args"></param>
        private static void TakesAWhile(RunHandler handler, object args)
        {
            if (handler != null)
            {
                RunHandler invoke = handler;
                invoke(args);
            }
        }

        /// <summary>
        /// 定义委托调用完毕后回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void CallBack(IAsyncResult ar)
        {
            if (ar == null)
            {
                throw new ArgumentException("ar");
            }

            CallBackDelegate id = ar.AsyncState as CallBackDelegate;

            id.EndInvoke(ar);
            if (CallBackFun != null)
            {
                RunHandler invoke = CallBackFun;
                invoke(_args);
            }
        }
        #endregion

这里只对委托使用做了一部分举例,更多的用法,大家可以多多实践,去发现新大陆,我这里就先不去发现了,因为接下来准备谈一下线程。

  • 8
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琳妹妹的辉哥哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值