1. 程式人生 > WINDOWS開發 >C#--回撥(轉載)

C#--回撥(轉載)

C#回撥函式的簡單講解與應用例子

——————————————————————————————————————

using System;
 
namespace CallBackTest { class Program //使用者層,執行輸入等操作 { static void Main(string[] args) { CalculateClass cc = new CalculateClass(); FunctionClass fc = new FunctionClass(); int result1 = cc.PrintAndCalculate(2,3,fc.GetSum); Console.WriteLine(
"呼叫了開發人員的加法函式,處理後返回結果:" + result1); int result2 = cc.PrintAndCalculate(2,fc.GetMulti); Console.WriteLine("呼叫了開發人員的乘法函式,處理後返回結果:" + result2); Console.ReadKey(); } } class FunctionClass //開發層處理,開發人員編寫具體的計算方法 { public int GetSum(int
a,int b) { return (a + b); } public int GetMulti(int a,int b) { return (a * b); } } #region 實際開發中,下面這個類會封裝起來,只提供函式介面。相當於系統底層 class CalculateClass { public delegate int SomeCalculateWay(int num1,int num2); //將傳入引數在系統底層進行某種處理,具體計算方法由開發者開發,函式僅提供執行計算方法後的返回值 public int PrintAndCalculate(int num1,int num2,SomeCalculateWay cal) { Console.WriteLine("系統底層處理:" + num1); Console.WriteLine("系統底層處理:" + num2); return cal(num1,num2);//呼叫傳入函式的一個引用 } //可以封裝更多的業務邏輯方法 } #endregion }

輸出結果:

技術分享圖片

下面詳細解釋一下(包含一些關於封裝的意義):

1、中間的FunctionClass中的GetSum()和GetMulti()兩個函式稱為回撥函式。可以看到整個程式中並沒有哪個地方通過類似GetSum(1,2)這種形式呼叫了該函式,只有將其當作另一個函式的引數來進行呼叫。如cc.PrintAndCalculate(2,3,fc.GetSum)。

下面是百度百科的定義:

回撥函式不是由該函式的實現方直接呼叫,而是在特定的事件或條件發生時由另外的一方呼叫的,用於對該事件或條件進行響應。

簡單來說,就是 public delegate int SomeCalculateWay(int num1,int num2) 這行程式碼,把 SomeCalculateWay 這幾個字元定義成一種型別,什麼型別呢?-> 帶了兩個int引數的函式型別。而PrintAndCalculate()函式的第三個引數是這種型別,GetSum(int,int)也是這種型別,所以GetSum這個函式可以被當做引數傳入,並且在列印完兩個數字後執行,被稱為回撥函式。

自此程式碼部分解釋完畢

有的同學可能會問了,那為什麼不直接寫int result1 = GetSum(1,2)呢?豈不是更方便?用這個回撥函式意義在哪呢?

這就涉及到封裝和實際開發的問題了 ↓

________________________________________________________

我們假想一下這個情況:

我們的專案是個核武器控制器,假設並沒有涉及到回撥函式。當用戶輸入1,2並且執行GetSum(1,2)的時候,這個工程會把1,2寫進核武器的發射係數裡,比如方向方位等,然後GetSum求得發射距離,之後進行發射。

看起來也很完美?沒什麼瑕疵?

不,有沒有想過萬一哪天操作失誤了呢。萬一哪天某個人輸入錯了,把-1,-2輸入進去了,現在倒好,本來要打到外面去的導彈打到自己家了,這個損失就是不可估量的了。

你可能又會說了,那讓程式設計師在客戶端(使用者端)判斷一下唄,比如加一句 if(a>0 && b>0) getsum(a,b);

那你有沒想過,萬一哪天這個程式設計師的程式碼寫錯了一行呢?或者派了一個像我一樣很菜的實習生過來寫程式碼?豈不是又要把導彈打到自己家了嗎hhhhhhhh。所以,在實際大型應用中,“把引數寫進核武器” 這個操作的程式碼並不是所有人都能接觸到的,只有專案裡最核心的工程師經過反覆測驗才能應用上去的,而且要對這些引數甚至是結果進行必要的判斷,並且如果要修改程式碼也是會經過慎重考量的,因為你一改,相當於整個專案底層都進行了改變,所有呼叫你函式的人執行效果也都會發生改變。

以上就是封裝的意義。(當然封裝還有其他意義這裡就不贅述了)

______________________________________________________________________

2、在實際開發中,CalculateClass這個類會被封裝起來,比如提供一個dll檔案給你,你通過引用dll來呼叫裡面的引數或者函式。一般專案裡的大佬/主程都會把這些底層的東西打包進dll,防止誤操作使得系統崩潰,也讓外界不能輕易訪問底層的東西。

在這個類中,public delegate int SomeCalculateWay(int num1,int num2); 這一語句聲明瞭一個委託,後面定義的SomeCalculateWay cal就代表著cal是一個帶有兩個int引數的函式。

3、在使用者層的main函式裡,使用者可以通過輸入引數2,3,然後獲取一個開發人員的方法比如getsum,然後把這些作為引數,呼叫底層的函式,再得到想要的效果。這樣子不管是使用者還是開發人員誤操作了,最後都會被底層的函式給判斷出來,從而不會執行錯誤的結果而造成損失。

4、當然封裝是回撥函式的一種用法,還有一種用法就是在有網路延遲的情況下,可以告訴外界某段程式碼已經在一定延遲後執行完畢,此時回撥函式就作為執行後接下來要進行的操作。