《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. ConsoleArr(arr);
  8. ComparisonHandler wx = new ComparisonHandler(DelegateSample.IsTrue);
  9. BubbleSort(arr, wx);
  10.       //C#2.0之前是这么写的
  11.       //BubbleSort(arr, new ComparisonHandler(IsTrue));  
  12. ConsoleArr(arr);
  13. Console.Read();
  14. }
  15. public delegate bool ComparisonHandler(int a, int b);
  16. public static bool IsTrue(int a, int b)
  17. {
  18. return a > b;
  19. }
  20. public static void BubbleSort(int[] items, ComparisonHandler comparisonMethod)
  21. {
  22. int i;
  23. int j;
  24. int temp;
  25. if (items == null)
  26. {
  27. return;
  28. }
  29. if (comparisonMethod == null)
  30. {
  31. throw new ArgumentNullException("comparisonMethod");
  32. }
  33. for (i = items.Length - 1; i >= 0; i--)
  34. {
  35. for (j = 1; j <= i; j++)
  36. {
  37. if (comparisonMethod(items[j - 1], items[j]))
  38. {
  39. temp = items[j - 1];
  40. items[j - 1] = items[j];
  41. items[j] = temp;
  42. }
  43. }
  44. }
  45. }
  46. public static void ConsoleArr(int[] arr)
  47. {
  48. foreach (var item in arr)
  49. {
  50. Console.Write(item+",");
  51. }
  52. Console.WriteLine();
  53. }
  54. }

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. //C# 2.0以后直接传递方法
  8. 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. comparionMethod = delegate(int first, int second)
  15. {
  16. return first < second;
  17. };
  18. BubbleSort(items, comparionMethod);
  19. for ( i = 0; i < items.Length; i++)
  20. {
  21. Console.WriteLine(items[i]);
  22. }
  23. Console.Read();
  24. }
  25. public static void BubbleSort(int[] items, ComparisonHandler comparisonMethod)
  26. {
  27. int i;
  28. int j;
  29. int temp;
  30. if (items == null)
  31. {
  32. return;
  33. }
  34. if (comparisonMethod == null)
  35. {
  36. throw new ArgumentNullException("comparisonMethod");
  37. }
  38. for (i = items.Length - 1; i >= 0; i--)
  39. {
  40. for (j = 1; j <= i; j++)
  41. {
  42. if (comparisonMethod(items[j - 1], items[j]))
  43. {
  44. temp = items[j - 1];
  45. items[j - 1] = items[j];
  46. items[j] = temp;
  47. }
  48. }
  49. }
  50. }
  51. }

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.
表达式树

来自为知笔记(Wiz)

时间: 2024-08-25 15:58:14

《C#本质论》读书笔记(12)委托和Lambda表达式的相关文章

读书笔记(委托)

委托回调静态方法和实例方法有何区别 当委托绑定静态方法时,内部的对象成员变量_target会被设置成null 当委托绑定实例方法是,_target将会设置成指向该实例方法所属的一个实例对象 当委托被执行时,该对象实例将会用来调用实例方法 1 class DelegateReturn 2 { 3 public delegate String GetStringDelegate(); 4 5 static string GetTypeName() 6 { 7 return typeof(Delega

[深入学习C#] 匿名函数、委托和Lambda表达式

匿名函数 匿名函数(Anonymous Function)是表示"内联"方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取决于转换的目标类型:如果是委托类型,则转换计算为引用匿名函数所定义的方法的委托:如果是表达式树类型,则转换将计算以对象结构形式表示方法结构的表达式树.  匿名函数有两种语法风格:Lambda表达式(lambda-expression)和匿名方法表达式(anonymous-method-ex

十二、C# 委托与Lambda表达式(匿名方法的另一种写法)

委托与Lambda表达式 1.委托概述 2.匿名方法 3.语句Lambda 4.表达式Lambda 5.表达式树 一.委托概述 相当于C++当中的方法指针,在C#中使用delegate 委托来提供相同的功能, 它将方法作为对象封装起来,允许在"运行时"间接地绑定一个方法调用. 声明的委托相当于一种自定义的数据类型. 1.背景 冒泡排序 1 static class SimpleSort1 2 { 3 public static void BubbleSort(int[] items)

转载 C#匿名函数 委托和Lambda表达式

转载原出处: http://blog.csdn.net/honantic/article/details/46331875 匿名函数 匿名函数(Anonymous Function)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取决于转换的目标类型:如果是委托类型,则转换计算为引用匿名函数所定义的方法的委托:如果是表达式树类型,则转换将计算以对象结构形式表示方法结构的表达式树.  匿名函数有两种语法风格

part01.03 委托与 Lambda 表达式(三):Lambda 表达式

"Lambda 表达式"是一个匿名函数,它可以包含表达式和语句,用于创建委托或表达式树类型 A. 用Lambda表达式代替匿名方法,复杂冗长的形式 格式:( 显式类型参数列表 )=>{ 语句 } 样例: // 带返回值的委托 Func<int, double, double> a = (m, n) => { return m * n; }; Console.WriteLine(a); Console.WriteLine(a(10, 25.2)); // 不带返回

委托、Lambda表达式、事件系列07,使用EventHandler委托

谈到事件注册,EventHandler是最常用的. EventHandler是一个委托,接收2个形参.sender是指事件的发起者,e代表事件参数. □ 使用EventHandler实现猜拳游戏 使用EventHandler实现一个猜拳游戏,每次出拳,出剪刀.石头.布这三者的其中一种. 首先抽象出一个被观察者,其中提供了事件,提供了执行事件的方法. public class FistGame { public string FistName { get; set; } public event

委托、匿名委托、Lambda 表达式、Expression表达式树之刨根问底

本篇不是对标题所述之概念的入门文章,重点在阐述它们的异同点和应用场景.各位看官,这里就不啰嗦了,直接上代码. 首先定义一个泛型委托类型,如下: public delegate T Function<T>(T a, T b); 实现泛型委托的主体代码,并调用: public static string Add(string a, string b) { return string.Format("{0} #### {1}",a,b); } //实名委托方式 Function&

委托、Lambda表达式、事件系列05,Action委托与闭包

来看使用Action委托的一个实例: static void Main(string[] args) { int i = 0; Action a = () => i++; a(); a(); Console.WriteLine(i); } 结果是期望能的2.但令人好奇的是:栈上的变量i是如何传递给Action委托的? 反编译进行查看,首先看Main方法对应的IL代码: 再看c_DisplayClass1的IL代码: 从中可以看出:→在托管堆上创建了一个名为c_DisplayClass1的实例→把

委托、Lambda表达式、事件系列04,委托链是怎样形成的, 多播委托

在"委托.Lambda表达式.事件系列01,委托是什么,委托的基本用法,委托的Method和Target属性"中,反编译委托,发现委托都是多播委托. 既然委托是多播委托,我们可以通过"+="把多个方法赋给委托变量,这样就形成了一个委托链, 它是怎样形成的?来看下面的例子: namespace ConsoleApplication3 { internal delegate void MySayDel(string msg); class Program { stati

委托、Lambda表达式、事件系列06,使用Action实现观察者模式

在"实现观察者模式(Observer Pattern)的2种方式"中,曾经通过接口的方式.委托与事件的方式实现过观察者模式.本篇体验使用Action实现此模式. 就举一个足球场上的例子,当裁判吹响终场哨,胜队庆祝,失败队落寞.把裁判看作是被观察者,比赛中的两队看作是观察者. 裁判作为被观察者需要提供一个Action委托供观察者方法注册. public class Referee { public Action DoSth; public void ISayGameOver() { Co