委托的实现匿名函数和朗姆达表达式
**委托(delegate):一个表示方法的数据类型。间接派生于System.Delegate
委托是一个引用类型,但不必用new来实例化它。直接传递名称,而不是现实实例化。这是c#2.0开始支持的一个新语法,成为委托推断(delegate inference)
1 namespace delegateEx 2 { 3 //委托声明 4 public delegate bool ComparisonHandler(int first,int second); 5 6 public static class DelegateSample 7 { // 8 public static void BubbleSort(int[] items, ComparisonHandler comparisonMethod) 9 { 10 int i; 11 int j; 12 int temp; 13 if (items == null) 14 { 15 return; 16 } 17 if (comparisonMethod == null) 18 { 19 throw new ArgumentNullException("comparisonMethod"); 20 } 21 22 for (i = items.Length - 1; i >= 0; i--) 23 { 24 for (j = 1; j <= i; j++) 25 { 26 //用委托实例 27 if (comparisonMethod(items[j - 1], items[j])) 28 { 29 temp = items[j - 1]; 30 items[j - 1] = items[j]; 31 items[j] = temp; 32 } 33 } 34 } 35 } 36 //匹配委托的参数GreaterThan(int first, int second) 37 public static bool GreaterThan(int first, int second) 38 { 39 return first > second; 40 } 41 } 42 class Program 43 { 44 static void Main(string[] args) 45 { 46 int[] items = new int[100]; 47 Random random = new Random(); 48 for (int i = 0; i < items.Length; i++) 49 { 50 items[i] = random.Next(1,100); 51 } 52 //将委托实例作为参数传递 53 DelegateSample.BubbleSort(items,DelegateSample.GreaterThan); 54 55 for (int i = 0; i < items.Length; i++) 56 { 57 Console.Write(" {0}",items[i]); 58 } 59 Console.ReadKey(); 60 } 61 } 62 }
**匿名方法:就是没有实际方法声明委托实例,或者说,他们的定义是直接内嵌在代码中的。
1 static void Main(string[] args) 2 { 3 int[] items = new int[5]; 4 Random random = new Random(); 5 ComparisonHandler comparisonMethod; 6 7 for (int i = 0; i < items.Length; i++) 8 { 9 items[i] = random.Next(1, 100); 10 } 11 //委托的定义直接内嵌在代码中。 12 comparisonMethod = delegate(int first, int second) 13 { 14 return first < second; 15 }; 16 BubbleSort(items,comparisonMethod); 17 18 for (int i = 0; i < items.Length; i++) 19 { 20 Console.Write(" {0}", items[i]); 21 } 22 Console.ReadKey(); 23 }
或者使用更直接的方法:
1 BubbleSort(items, 2 delegate(int first, int second) 3 { 4 return first < second; 5 });
注意,在任何情况下,参数和返回值类型必须兼容于委托的数据类型。
*匿名方法是允许省略参数列表的,但是返回值类型需要与委托一致。
**系统定义的委托:
System.Func 在.NET 3.5中代表有返回类型的委托
System.Action代表无返回类型的委托。
不能将一个委托类型赋给另一个委托类型的变量,即使类型参数匹配。
*为委托使用可变性[还没理解]
Action<object> broadAction=delegate(object data) { Console.WriteLine(data); } Action<string> narrowAction=broadAction; Func<string>narrowFunction=delegate() { return Console.WriteLine(); }; Func<object> broadFunction=narrowAction; Func<object ,string >func1= degate(object data) { return data.ToString(); }; Func<string,object>func2=fun1;
**Lamda表达式 (关键字=>) :分为Lamda表达式和Lamda语句
与上述等价的Lamda语句(用于)
1 BubbleSort(items, 2 (int first, int second)=> 3 { 4 return first < second; 5 } 6 );
*省略参数类型:通常,只要编译器能推断出参数类型,或者能将参数类型隐式转换成期望的数据类型,语句Lamda就不需要参数类型。如果要制定类型,那么制定的类型必须和委托类型完全匹配。只要Lamda语句包含了一个类型,则所有的类型都要加上。
1 BubbleSort(items, 2 (first,second)=> 3 { 4 return first < second; 5 } 6 );
*c#要求用一对圆括号来封闭Lamda表达式的参数类表,不管是否指定了这些参数的数据类型。圆括号的另外一个规则是,当编译器能推断出数据类型,而且只有一个输入参数的时候,语句Lamda可以不带圆括号。
Func<string> getUserInput=
()=>
{
string input;;
do
{ input=Console.ReadLine();}
while(input.Trim()==0);
return input;
}
*Lamda表达式(满足……条件)
- BubbleSort(items,
- (int first, int second)=> first < second );
**Lamda表达式本身没有类型
所以 . 运算符不会被编译,调用Object的方法也不行。
不能出现在is的左侧
Lamda表达式一旦被赋值或者转型,就会有Lamda表达式的类型这种非正式的说法
不能赋值给隐式类型的变量
如果目的在Lamda表达式的外部,c#就不允许在匿名函数内部使用跳转语句(break,continue,goto)
*外部变量:在Lamda表达式(包括参数)的外部声明,但是Lamda表达式的内部捕捉(访问)的局部变量称为外部变量。this也是一个外部变量。
int comparisonCount=0;
...
BubbleSort(item,
(int first ,int second)=>
{
comparisonCount++;
return first<second;
}
);
Console.WriteLine(comparisonCount);
**表达式树[不理解]
“解释”是c#引入表达式树(expression trees)这一概念的重要动机。如果一种Lamda表达式代表的是与表达式有关的数据,而不是编译好的代码,这中Lamda表达式就是表达式树。由于表达式树代表的是数据而非编译好的代码,所以可以把数据转换成一种替代格式。例如,转换成SQL代码。
persons.Where(person=>person.Name.ToUpper()=="INIGO MONTOYA")
select *from Person where upper(Name)='INIGO MONTOYA'