委託與線程的見解(上)——委託

委託相關

        對於委託,我們都知道他是一個引用類型,具有引用類型所具有的通性。需要知道的是它保存的不是實際值,只是是保存對存儲在託管堆中的對象的引用。或說的直接點,委託就相當於叫人幫忙,讓你幫你做一些事情。我這裏就舉一些委託操作的小實例,來簡單的說一下。

        在開始舉例之前,再說一下,委託一般包含三個方法,分別是BeginInvoke、EndInvoke、Invoke。EndInvoke就不必說了,一看就知道是幹嘛的。Invoke 和BeginInvoke,前一個是同步委託,後一個是異步委託,何爲同步,何爲異步呢?其實也可從字面意思理解,同步就是同時進行的,不能說你先執行,我後執行,那麼異步就是與同步相對的,但是也不全相對,因爲異步的執行不受主進程的影響,執行全看它個人了。

        這裏所說的委託都是自己新建的委託,但還有種委託,是C#控件自帶的委託,也分有同步異步之分,控件委託用處很大,在後面說線程的時候會說到,因爲在使用線程時,有時控件委託是必要的。

        下面先單獨說一個委託的例子吧:

第一步:

        //創建委託
        private delegate void testDelegate();

第二步:

        //定義委託API
        private event testDelegate TestClick;
        public void OnTest()
        {
            testDelegate handler = TestClick;
            if (handler != null)
                handler();
        }

第三步:

            //調用委託API
            OnTest();

第四步:

 

 

 

 

這是委託最常用也是很實用的一個例子,我們可以通過這種方式,實現不同窗體之間的交互,比如在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

這裏只對委託使用做了一部分舉例,更多的用法,大家可以多多實踐,去發現新大陸,我這裏就先不去發現了,因爲接下來準備淺談一下線程。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章