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;
- }
- );