您的位置:首页 - 教程 - C# - 正文
《C#本质论》读书笔记(12)委托和Lambda表达式


12.1.
委托概述
 

12.1.2 委托的数据类型

为了减少重复代码数量,可以将比较方法作为参数传递给 BubbleSort()方法。此外,为了将方法作为参数传递,必须有一个能够标识方法的数据类型——也就是委托。这里的委托类型是 ComparisonHandler 。
 c# 2.0之前的写法
  1. class DelegateSample  
  2.     {  
  3.         static void Main(string[] args)  
  4.         {  
  5.             //int[] arr = { 10, 20, 30, 40, 50 };  
  6.             int[] arr = { 50, 40, 30, 20, 10 };  
  7.   
  8.             ConsoleArr(arr);  
  9.   
  10.             ComparisonHandler wx = new ComparisonHandler(DelegateSample.IsTrue);  
  11.             BubbleSort(arr, wx);  
  12.       //C#2.0之前是这么写的
  13.       //BubbleSort(arr, new ComparisonHandler(IsTrue));  
  14.   
  15.             ConsoleArr(arr);  
  16.   
  17.             Console.Read();  
  18.         }  
  19.   
  20.         public delegate bool ComparisonHandler(int a, int b);  
  21.   
  22.         public static bool IsTrue(int a, int b)  
  23.         {  
  24.                 return a > b;  
  25.         }  
  26.   
  27.         public static void BubbleSort(int[] items, ComparisonHandler comparisonMethod)  
  28.         {  
  29.             int i;  
  30.             int j;  
  31.             int temp;  
  32.             if (items == null)  
  33.             {  
  34.                 return;  
  35.             }  
  36.             if (comparisonMethod == null)  
  37.             {  
  38.                 throw new ArgumentNullException("comparisonMethod");  
  39.             }  
  40.             for (i = items.Length - 1; i >= 0; i--)  
  41.             {  
  42.                 for (j = 1; j <= i; j++)  
  43.                 {  
  44.                     if (comparisonMethod(items[j - 1], items[j]))  
  45.                     {  
  46.                         temp = items[j - 1];  
  47.                         items[j - 1] = items[j];  
  48.                         items[j] = temp;  
  49.                     }  
  50.                 }  
  51.             }  
  52.         }  
  53.   
  54.         public static void ConsoleArr(int[] arr)  
  55.         {  
  56.             foreach (var item in arr)  
  57.             {  
  58.                 Console.Write(item+",");  
  59.             }  
  60.             Console.WriteLine();  
  61.         }  
  62.     }  


C#2.0以后可以直接调用方法
 
  1. public static bool AlphabeticalIsTrue(int a,int b)  
  2.         {  
  3.             int comparison;  
  4.             comparison = (a.ToString().CompareTo(b.ToString()));  
  5.             return comparison > 0;  
  6.         }  
  7.   
  8.   
  9. //C# 2.0以后直接传递方法  
  10.             BubbleSort(arr, AlphabeticalIsTrue); 

12.1.3 委托内部机制

第一个属性属于 System.Reflection.MethodiInfo 类型,MethodInfo 定义一个特定方法的签名,其中包括方法的名称、参数和返回类型。除了 MethodInfo,委托还需要一个对象实例,其中包含了要调用的方法。这正式第二个属性 Target 的用途。在静态方法的情况下,Target 对应于类型自身。

  1. // 摘要:   
  2. //     初始化一个委托,该委托对指定的类实例调用指定的实例方法。  
  3. //  
  4. // 参数:   
  5. //   target:  
  6. //     类实例,委托对其调用 method。  
  7. //  
  8. //   method:  
  9. //     委托表示的实例方法的名称。  
  10. //  
  11. // 异常:   
  12. //   System.ArgumentNullException:  
  13. //     target 为 null。 - 或 - method 为 null。  
  14. //  
  15. //   System.ArgumentException:  
  16. //     绑定到目标方法时出错。  
  17. [SecuritySafeCritical]  
  18. protected Delegate(object target, string method);  
  19. //  
  20. // 摘要:   
  21. //     初始化一个委托,该委托从指定的类调用指定的静态方法  
  22. //  
  23. // 参数:   
  24. //   target:  
  25. //     System.Type,它表示定义 method 的类。  
  26. //  
  27. //   method:  
  28. //     委托表示的静态方法的名称。  
  29. //  
  30. // 异常:   
  31. //   System.ArgumentNullException:  
  32. //     target 为 null。 - 或 - method 为 null。  
  33. //  
  34. //   System.ArgumentException:  
  35. //     target 不是 RuntimeType。 请参见 反射中的运行时类型。 - 或 - target 表示开放式泛型类型。  
  36. [SecuritySafeCritical]  
  37. protected Delegate(Type target, string method);  


12.2.
匿名方法
 

传递一个匿名方法

  1. class Program 
  2. {  
  3.     public delegate bool ComparisonHandler(int a, int b);  
  4.     static void Main(string[] args)  
  5.     {  
  6.         int i;  
  7.         int[] items = new int[5];  
  8.         ComparisonHandler comparionMethod;  
  9.         for (i = 0; i < items.Length; i++)  
  10.         {  
  11.             Console.WriteLine("Enter an integer:");  
  12.             items[i] = int.Parse(Console.ReadLine());  
  13.         }  
  14.   
  15.        comparionMethod = delegate(int first, int second)   
  16.         {                                                                   
  17.             return first < second;                                    
  18.         };                                                                  
  19.         BubbleSort(items, comparionMethod);                   
  20.   
  21.         for ( i = 0; i < items.Length; i++)  
  22.         {  
  23.             Console.WriteLine(items[i]);  
  24.         }  
  25.   
  26.         Console.Read();  
  27.           
  28.     }  
  29.   
  30.     public static void BubbleSort(int[] items, ComparisonHandler comparisonMethod)  
  31.     {  
  32.         int i;  
  33.         int j;  
  34.         int temp;  
  35.         if (items == null)  
  36.         {  
  37.             return;  
  38.         }  
  39.         if (comparisonMethod == null)  
  40.         {  
  41.             throw new ArgumentNullException("comparisonMethod");  
  42.         }  
  43.         for (i = items.Length - 1; i >= 0; i--)  
  44.         {  
  45.             for (j = 1; j <= i; j++)  
  46.             {  
  47.                 if (comparisonMethod(items[j - 1], items[j]))  
  48.                 {  
  49.                     temp = items[j - 1];  
  50.                     items[j - 1] = items[j];  
  51.                     items[j] = temp;  
  52.                 }  
  53.             }  
  54.         }  
  55.     }  
  56. }  


12.3.
系统定义的委托:Func 和 Action 声明
 
在.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说明

公共语言运行时提供 Invoke 每种委托类型,具有相同的签名与委托的方法。 您不需要显式调用此方法,从 C#、 Visual Basic 或 Visual c + +,因为编译器会自动调用。 Invoke 方法就很有用 反射 如果想要查找的委托类型签名。

https://msdn.microsoft.com/zh-cn/library/system.delegate.aspx


12.4.
语句Lambda
 

1.无参数的语句

即使无参数的语句lambda(代表无输入参数的委托),也要输入一对空白的圆括号
  1. static void Main(string[] args)  
  2. {  
  3.     //...  
  4.     Func<string> getUserInput =  
  5.         () =>  
  6.         {  
  7.             string input;  
  8.             do  
  9.             {  
  10.                 input = Console.ReadLine();  
  11.             }  
  12.             while (input.Trim().Length == 0);  
  13.             return input;  
  14.         };  
  15.     //...  
  16. }  
圆括号规则的一个例外是,当编译器能推断出数据类型,而且只有一个参数的时候。语句Lambda可以不带圆括号。

2.只有一个参数的语句

  1. IEnumerable<Process> processes = Process.GetProcesses()  
  2. .Where(process => { return process.WorkingSet64 > 100000000; });  
Where() 返回的是对物理内存占用超过 1GB 的进程的一个查询

12.5.
表达式Lambda
 
语句Lambda含有一个语句块,所以可以包含零个或者更多的语句,
表达式Lambda比语句Lambda更进一步。语句Lambda的代码块都只由一个return语句构成。其实在这种lambda块中,唯一需要就是准备返回的表达式。其他可以省略。
使用一个表达式Lambda来传递委托
  1. BubbleSort(items, (first, second) => first > second);  
语句lambda的比较

  1. BubbleSort(items, (first, second) => 
  2.     {
  3.         return first > second;
  4.     }
  5. );  


12.6.
表达式树
 










评论: