官术网_书友最值得收藏!

6.6 委托

委托(delegate)是一種存儲函數引用的類型。這聽起來相當深奧,但其機制是非常簡單的。委托最重要的用途在本書后面介紹到事件和事件處理時才能解釋清楚,但這里也將介紹有關委托的許多內容。委托的聲明非常類似于函數,但不帶函數體,且要使用delegate關鍵字。委托的聲明指定了一個返回類型和一個參數列表。

定義了委托后,就可以聲明該委托類型的變量。接著把這個變量初始化為與委托具有相同返回類型和參數列表的函數引用。之后,就可以使用委托變量調用這個函數,就像該變量是一個函數一樣。

有了引用函數的變量后,就可以執行無法用其他方式完成的操作。例如,可以把委托變量作為參數傳遞給一個函數,這樣,該函數就可以使用委托調用它引用的任何函數,而且在運行之前不必知道調用的是哪個函數。下面的示例使用委托訪問兩個函數中的一個。

試一試:使用委托來調用函數:Ch06Ex05\Program.cs

(1)在C:\BegVCSharp\Chapter06目錄中創建一個新的控制臺應用程序Ch06Ex05。

(2)把下列代碼添加到Program.cs中:

        class Program
        {
          delegate double ProcessDelegate(double param1, double param2);
          static double Multiply(double param1, double param2) => param1 * param2;
          static double Divide(double param1, double param2) => param1 / param2;
          static void Main(string[] args)
          {
              ProcessDelegate process;
              WriteLine("Enter 2 numbers separated with a comma:");
              string input = ReadLine();
              int commaPos = input.IndexOf(', ');
              double param1 = ToDouble(input.Substring(0, commaPos));
              double param2 = ToDouble(input.Substring(commaPos + 1,
                                      input.Length - commaPos - 1));
              WriteLine("Enter M to multiply or D to divide:");
              input = ReadLine();
              if (input == "M")
                process = new ProcessDelegate(Multiply);
              else
                process = new ProcessDelegate(Divide);
              WriteLine($"Result: {process(param1, param2)}");
              ReadKey();
          }
        }

(3)執行代碼,在看到提示時輸入值,結果如圖6-10所示。

圖6-10

示例說明

這段代碼定義了一個委托ProcessDelegate,其返回類型和參數與函數Multiply()和Divide()相匹配。注意Multiply()和Divide()方法使用了C# 6引入的=>(Lambda箭頭)。

        static double Multiply(double param1, double param2) => param1 * param2;

委托的定義如下所示:

        delegate double ProcessDelegate(double param1, double param2);

delegate關鍵字指定該定義是用于委托的,而不是用于函數的(該定義所在的位置與函數定義相同)。接著,該定義指定double返回類型和兩個double參數。實際使用的名稱可以是任意的,所以可以給委托類型和參數指定任意名稱。這里委托名是ProcessDelegate, double參數名是param1和param2。

Main()中的代碼首先使用新的委托類型聲明一個變量:

        static void Main(string[] args)
        {
          ProcessDelegate process;

接著用一些比較標準的C#代碼請求由逗號分隔的兩個數字,并將這些數字放在兩個double變量中:

        WriteLine("Enter 2 numbers separated with a comma:");
        string input = ReadLine();
        int commaPos = input.IndexOf(', ');
        double param1 = ToDouble(input.Substring(0, commaPos));
        double param2 = ToDouble(input.Substring(commaPos + 1,
                                  input.Length - commaPos - 1));

注意:為說明問題,這里沒有驗證用戶輸入的有效性。如果這些是“現實中的”代碼,就應花費更多時間來確保在局部變量param1和param2中得到有效的值。

接著詢問用戶,這兩個數字是要相乘還是相除:

        WriteLine("Enter M to multiply or D to divide:");
        input = ReadLine();

根據用戶的選擇,初始化process委托變量:

        if (input == "M")
          process = new ProcessDelegate(Multiply);
        else
          process = new ProcessDelegate(Divide);

要把一個函數引用賦給委托變量,需要使用略顯古怪的語法。這個過程比較類似于給數組賦值,必須使用new關鍵字創建一個新委托。在這個關鍵字的后面,指定委托類型,提供一個引用所需函數的參數,這里也就是Multiply()或Divide()函數。注意這個參數與委托類型或目標函數的參數不匹配,這是委托賦值的一種獨特語法,參數是要使用的函數名且不帶括號。

實際上,這里可以使用略微簡單的語法:

        if (input == "M")
          process = Multiply;
        else
          process = Divide;

編譯器會發現,process變量的委托類型匹配兩個函數的簽名,于是自動初始化一個委托。可以自行確定使用哪種語法,但一些人喜歡使用較長的版本,因為它更容易一眼看出會發生什么。

最后,使用該委托調用所選的函數。無論委托引用的是什么函數,該語法都是有效的:

          WriteLine($"Result: {process(param1, param2)}");
          ReadKey();
        }

這里把委托變量看成一個函數名。但與函數不同,我們還可以對這個變量執行更多操作,例如,通過參數將其傳遞給一個函數,如下例所示:

        static void ExecuteFunction(ProcessDelegate process)
                    => process(2.2, 3.3);

就像選擇一個要使用的“插件”一樣,通過把函數委托傳遞給函數,就可以控制函數的執行。例如,一個函數要對字符串數組按照字母進行排序。對列表排序有幾個不同的方法,它們的性能取決于要排序的列表特性。使用委托可以把一個排序算法函數委托傳遞給排序函數,指定要使用的函數。

委托有許多用途,但如前所述,它們的大多數常見用途主要與事件處理有關,具體內容詳見第13章。

主站蜘蛛池模板: 黄陵县| 汨罗市| 泾阳县| 永州市| 易门县| 贵阳市| 榆社县| 克什克腾旗| 河南省| 灵川县| 襄垣县| 新巴尔虎右旗| 佳木斯市| 上饶县| 武宁县| 秦皇岛市| 镇宁| 马鞍山市| 铁岭县| 马尔康县| 大关县| 临海市| 海晏县| 潼南县| 漠河县| 当雄县| 南涧| 新田县| 萨迦县| 满城县| 武平县| 金川县| 五指山市| 苗栗市| 光泽县| 全南县| 射洪县| 盐源县| 工布江达县| 额尔古纳市| 杨浦区|