12.1.2 委托的數據類型
為了減少重復代碼數量,可以將
比較方法作為參數傳遞給 BubbleSort()方法。此外,為了將方法作為參數傳遞,必須有一個能夠標識方法的數據類型——也就是委托。這裡的委托類型是 ComparisonHandler 。
c# 2.0之前的寫法- class DelegateSample
- {
- static void Main(string[] args)
- {
- //int[] arr = { 10, 20, 30, 40, 50 };
- int[] arr = { 50, 40, 30, 20, 10 };
-
- ConsoleArr(arr);
-
- ComparisonHandler wx = new ComparisonHandler(DelegateSample.IsTrue);
- BubbleSort(arr, wx);
- //C#2.0之前是這麼寫的
- //BubbleSort(arr, new ComparisonHandler(IsTrue));
-
- ConsoleArr(arr);
-
- Console.Read();
- }
-
- public delegate bool ComparisonHandler(int a, int b);
-
- public static bool IsTrue(int a, int b)
- {
- return a > b;
- }
-
- public static void BubbleSort(int[] items, ComparisonHandler comparisonMethod)
- {
- int i;
- int j;
- int temp;
- if (items == null)
- {
- return;
- }
- if (comparisonMethod == null)
- {
- throw new ArgumentNullException("comparisonMethod");
- }
- for (i = items.Length - 1; i >= 0; i--)
- {
- for (j = 1; j <= i; j++)
- {
- if (comparisonMethod(items[j - 1], items[j]))
- {
- temp = items[j - 1];
- items[j - 1] = items[j];
- items[j] = temp;
- }
- }
- }
- }
-
- public static void ConsoleArr(int[] arr)
- {
- foreach (var item in arr)
- {
- Console.Write(item+",");
- }
- Console.WriteLine();
- }
- }
C#2.0以後可以直接調用方法 - public static bool AlphabeticalIsTrue(int a,int b)
- {
- int comparison;
- comparison = (a.ToString().CompareTo(b.ToString()));
- return comparison > 0;
- }
-
-
- //C# 2.0以後直接傳遞方法
- BubbleSort(arr, AlphabeticalIsTrue);
12.1.3 委托內部機制
第一個屬性屬於 System.Reflection.MethodiInfo 類型,MethodInfo 定義一個特定方法的簽名,其中包括方法的名稱、參數和返回類型。除了 MethodInfo,委托還需要一個對象實例,其中包含了要調用的方法。這正式第二個屬性 Target 的用途。在靜態方法的情況下,Target 對應於類型自身。
- // 摘要:
- // 初始化一個委托,該委托對指定的類實例調用指定的實例方法。
- //
- // 參數:
- // target:
- // 類實例,委托對其調用 method。
- //
- // method:
- // 委托表示的實例方法的名稱。
- //
- // 異常:
- // System.ArgumentNullException:
- // target 為 null。 - 或 - method 為 null。
- //
- // System.ArgumentException:
- // 綁定到目標方法時出錯。
- [SecuritySafeCritical]
- protected Delegate(object target, string method);
- //
- // 摘要:
- // 初始化一個委托,該委托從指定的類調用指定的靜態方法。
- //
- // 參數:
- // target:
- // System.Type,它表示定義 method 的類。
- //
- // method:
- // 委托表示的靜態方法的名稱。
- //
- // 異常:
- // System.ArgumentNullException:
- // target 為 null。 - 或 - method 為 null。
- //
- // System.ArgumentException:
- // target 不是 RuntimeType。 請參見 反射中的運行時類型。 - 或 - target 表示開放式泛型類型。
- [SecuritySafeCritical]
- protected Delegate(Type target, string method);
- class Program
- {
- public delegate bool ComparisonHandler(int a, int b);
- static void Main(string[] args)
- {
- int i;
- int[] items = new int[5];
- ComparisonHandler comparionMethod;
- for (i = 0; i < items.Length; i++)
- {
- Console.WriteLine("Enter an integer:");
- items[i] = int.Parse(Console.ReadLine());
- }
-
- comparionMethod = delegate(int first, int second)
- {
- return first < second;
- };
- BubbleSort(items, comparionMethod);
-
- for ( i = 0; i < items.Length; i++)
- {
- Console.WriteLine(items[i]);
- }
-
- Console.Read();
-
- }
-
- public static void BubbleSort(int[] items, ComparisonHandler comparisonMethod)
- {
- int i;
- int j;
- int temp;
- if (items == null)
- {
- return;
- }
- if (comparisonMethod == null)
- {
- throw new ArgumentNullException("comparisonMethod");
- }
- for (i = items.Length - 1; i >= 0; i--)
- {
- for (j = 1; j <= i; j++)
- {
- if (comparisonMethod(items[j - 1], items[j]))
- {
- temp = items[j - 1];
- items[j - 1] = items[j];
- items[j] = temp;
- }
- }
- }
- }
- }
在.NET3.5(C# 3.0)中,存在一系列名為“Action”和“Func”的泛型委托。
System.Func 代表有返回類型的委托,而
System.Action 代表無返回類型的委托。
.NET 委托類型不具備結構的相等性(structural equality)。不能將某個委托類型對象引用轉換為不相關的委托類型,即使這兩個委托類型的形參和返回類型完全一致。例如,這裡就不能將
ComparisonHandler 引用直接賦給一個
Func<int,int,bool>變量。遺憾的是,需要結構一致但不相關的委托類型的情況下,為了使用給定的委托,唯一的辦法是創建一個新委托。讓它引用舊委托的 Invoke 方法。假定有一個
ComparisonHandler 變量
c,需要把 c 賦值給
Func<int,int,bool>類型的變量
f ,那麼可以寫成
f = c.Invoke;。
公共語言運行時提供 Invoke 每種委托類型,具有相同的簽名與委托的方法。 您不需要顯式調用此方法,從 C#、 Visual Basic 或 Visual c + +,因為編譯器會自動調用。 Invoke 方法就很有用 反射 如果想要查找的委托類型簽名。
https://msdn.microsoft.com/zh-cn/library/system.delegate.aspx
1.無參數的語句
即使無參數的語句lambda(代表無輸入參數的委托),也要輸入一對空白的圓括號
- static void Main(string[] args)
- {
- //...
- Func<string> getUserInput =
- () =>
- {
- string input;
- do
- {
- input = Console.ReadLine();
- }
- while (input.Trim().Length == 0);
- return input;
- };
- //...
- }
圓括號規則的一個例外是,當編譯器能推斷出數據類型,而且只有一個參數的時候。語句Lambda可以不帶圓括號。
2.只有一個參數的語句
- IEnumerable<Process> processes = Process.GetProcesses()
- .Where(process => { return process.WorkingSet64 > 100000000; });
Where() 返回的是對物理內存占用超過 1GB 的進程的一個查詢
語句Lambda含有一個語句塊,所以可以包含零個或者更多的語句,表達式Lambda比語句Lambda更進一步。語句Lambda的代碼塊都只由一個return語句構成。其實在這種lambda塊中,唯一需要就是准備返回的表達式。其他可以省略。
使用一個表達式Lambda來傳遞委托- BubbleSort(items, (first, second) => first > second);
- BubbleSort(items, (first, second) =>
- {
- return first > second;
- }
- );