C#將C++動態庫的回調函數封裝成事件

  關於C#調用C++動態庫的文章不少,調用動態庫中回調函數的方法也不在少數。但大多數調用回調函數的方法依然保留了C++的語法特色。異步

  好比有一段C++的回調函數代碼,爲了表達它的意思,我把註釋也粘貼了進來:函數

    /*********************************************************************************************************
   ** Function name:     epcBuzzerAsyncOn
   ** Descriptions:      本函數使蜂鳴器蜂鳴指定時間
   ** input parameters:        dwOntime    蜂鳴器持續蜂鳴的時間(ms),其中0表示一直蜂鳴
   ** output parameters:    無
   ** Returned value:          TRUE:成功;FALSE:失敗
   ** Note:                    本函數以異步方式執行,不會被阻塞
   *********************************************************************************************************/

EPCBUZZERLIB_API BOOL epcBuzzerAsyncOn (DWORD dwOntime);

  /********************************************************************************************************* ** Function name: epcBuzzerSetCallBackFunc ** Descriptions: 設置回調函數指針,當異步的蜂鳴器操做任務完成後,會調用該回調函數通知用戶程序。 ** input parameters: lpfnNotify 回調函數指針,若是是NULL,則表示不須要通知用戶程序。函數類 ** 型爲void (*lpfnNotify)(BOOL bResult),bResult爲執行結果, ** TRUE表示執行成功,FALSE表示執行失敗 ** output parameters: 無 ** Returned value: 無 *********************************************************************************************************/ EPCBUZZERLIB_API VOID epcBuzzerSetCallBackFunc( void (*lpfnNotify)(BOOL));

 

  通常的文章都會教你轉換成以下代碼,這些方法都屬於Buzzer類:this

     /// <summary>
        /// 使蜂鳴器蜂鳴指定時間,異步執行,不會阻塞當前線程.
        /// </summary>
        /// <param name="onTime">蜂鳴時間(ms).</param>
        /// <returns>true:蜂鳴成功,false:蜂鳴失敗</returns>
        [System.Runtime.InteropServices.DllImport("Lib\\epcBuzzerLib.dll", SetLastError = true)]
        private static extern bool epcBuzzerAsyncOn(int onTime);

     /// <summary>
        /// 先申明一個委託,該委託定義了蜂鳴完成回調函數的指針和數據類型
        /// </summary>
        /// <param name="result">if set to <c>true</c> [result].</param>
        public delegate void BuzzerHandler(bool result);

        /// <summary>
        /// 再設置蜂鳴完成回調函數.
        /// </summary>
        /// <param name="handler">The handler.</param>
        [System.Runtime.InteropServices.DllImport("Lib\\epcBuzzerLib.dll", SetLastError = true)]
        private static extern void epcBuzzerSetCallBackFunc(BuzzerHandler handler);

 

  而後在主程序中如此調用:spa

//先定義一個知足委託類型的函數
public void BuzzerNotify(bool result)
{
   //在這裏編寫蜂鳴完成後你想要執行的代碼...我這裏根據result隨便寫幾行。
if(result) {   MessageBox.Show("蜂鳴成功"); } else {   MessageBox.Show("蜂鳴失敗"); } } //在按鈕事件中調用回調函數 private void onButton_Click(object sender, EventArgs e) {   Buzzer.epcBuzzerCallBackFunc(this.BuzzerNotify);   Buzzer.epcBuzzerAsyncOn(3000); }

這樣,在蜂鳴器蜂鳴3000ms以後,就會調用BuzzerNotify,並將一個bool結果傳進去。而後你能夠在BuzzerNotify中作你想作的事。線程

  雖然這樣也可以解決問題,可是我總感受很彆扭,總以爲個人代碼裏有C++風格,這讓有代碼潔癖的我感受到渾身不自在。因此,我決定重構一下這段代碼,讓它符合C#的風格。指針

  重構的思想是這樣的,雖然我不太能徹底理解回調函數這個東西,可是我能隱約感受到它就是一個事件觸發機制,好比上面那段代碼,就能夠理解爲當蜂鳴完成後,就會通知BuzzerNotify,讓它開始執行。只不過BuzzerNotiy是在主函數中定義的一個函數,它不能像事件那樣能夠註冊,你全部想在蜂鳴器完成後作的工做,都必須寫在這個函數裏面。很明顯,如此糟糕的擴展性,徹底不是C#的風格。因此,我要作的,就是將BuzzerNotify變成Buzzer類的一個事件,讓它可使用+=這樣的神器!code

  其實作法也是蠻簡單的,我把代碼一貼出來你們立馬就能明白了。如下是Buzzer類的代碼對象

        /// <summary>
        /// 申明蜂鳴完成回調函數指針和數據類型
        /// </summary>
        /// <param name="result">if set to <c>true</c> [result].</param>
        public delegate void BuzzerHandler(bool result);

        /// <summary>
        /// 蜂鳴完成時觸發該事件.
        /// </summary>
        public static event BuzzerHandler BuzzingComplete;     
  
        /// <summary>
        /// 使蜂鳴器蜂鳴指定時間,異步執行,不會阻塞當前線程.
        /// </summary>
        /// <param name="onTime">蜂鳴時間(ms).</param>
        /// <returns>true:蜂鳴成功,false:蜂鳴失敗</returns>
        public static bool TurnOn(int time)
        {
            Buzzer.BuzzingCompleteSetCallBack();
            return Buzzer.epcBuzzerAsyncOn(time);
        }    

        /// <summary>
        /// 使蜂鳴器蜂鳴指定時間,異步執行,不會阻塞當前線程.
        /// </summary>
        /// <param name="onTime">蜂鳴時間(ms).</param>
        /// <returns>true:蜂鳴成功,false:蜂鳴失敗</returns>
        [System.Runtime.InteropServices.DllImport("Lib\\epcBuzzerLib.dll", SetLastError = true)]
        private static extern bool epcBuzzerAsyncOn(int onTime);

        /// <summary>
        /// 定義蜂鳴完成回調函數,用來處理事件.這個方法比較關鍵,它至關於把以前的BuzzerNotify,只不過把它封裝進Buzzer類了。
        /// </summary>
        /// <param name="result">if set to <c>true</c> [result].</param>
        private static void Event(bool result)
        {
            if (BuzzingComplete != null)
            {
                BuzzingComplete(result);
            }
        }


        /// <summary>
        /// 蜂鳴完成回調函數.
        /// </summary>
        private static void BuzzingCompleteSetCallBack()
        {
            Buzzer.epcBuzzerSetCallBackFunc(Event);
        }

        /// <summary>
        /// 設置蜂鳴完成回調函數.
        /// </summary>
        /// <param name="handler">The handler.</param>
        [System.Runtime.InteropServices.DllImport("Lib\\epcBuzzerLib.dll", SetLastError = true)]
        private static extern void epcBuzzerSetCallBackFunc(BuzzerHandler handler);

雖然多了不少代碼,但爲了面向對象,這絕對是值得的!
在主函數中能夠如此調用:blog

private void FirstThing(bool result)
{
    MessageBox.Show("Do my first thing");
}

private void SecondThing(bool result)
{
    MessageBox.Show("Do my second thing");
}

private void onButton_Click(object sender, EventArgs e)
{
     Buzzer.BuzzingComplete += this.FirstThing;
     Buzzer.BuzzingComplete += this.SecondThing;
     Buzzer.TurnOn(3000);
}

如此一來,主程序中的代碼看上去就舒服多了。值得一提的是,若是你連續點幾回這個OKButton的話,這兩個方法會被重複註冊。事件

相關文章
相關標籤/搜索