深入理解C#(十六) *第九章(C# 3:Lambda表达式和表达树) lambda=λ
作为委托的lambda表达式 Func<…>委托类型简介 .NET3.5的System命名空间中,有5个泛型Func委托类型。 每个委托签名都获取0~4个参数,其类型使用类型参数来指定。最后一个类型参数用作每种情况下的返回类型。 例如:Func<string,double,int>等价于public delegate int SomeDelegate(string arg1,double arg2)
转换成lambda表达式 用匿名方法来创建委托实例
1 2 3 Func<string,int> returnLength; returnLength=delegate(string text){return text.Length;}; Console.WriteLine(returnLength("Hello"));
Lambda表达式最冗长的形式是:(显示类型的参数列表)=》{语句}
例子:
1 2 3 4 Func<string, int> returnLength; returnLength = (string text) => { return text.Length; }; Console.WriteLine(returnLength("Hello"));
Lambda表达式有着和匿名方法控制返回语句一样的规则:不能从Lambda表达式返回void类型
使用单一表达式作为主体 大多数情况可以用一个表达式来表示整个主体,该表达式的值是Lambda的结果
1 (string text)=>text.Length
隐式类型的参数列表 编译器能推断出参数类型,可以不用显示声明参数类型,注意: 隐式和显示类型参数不能一起用。此外要是有out或ref参数,只能使用显示参数。
单一参数的快捷语法 如果lambda表达式只需要一个参数,且那个参数可以隐式指定类型,可以省略圆括号
现在,例子简化成:
1 2 3 4 Func<string, int> returnLength; returnLength = text => text.Length; Console.WriteLine(returnLength("Hello"));
高阶函数 Lambda表达式主体可以包含另一个Lambda表达式,另外,Lambda表达式的参数可以是另一个委托
使用List和事件的简单例子 列表的过滤、排序和操作 List的FindAll方法,获取一个Predicate,并返回一个新列表,包含原始列表中与谓词匹配的所有元素。Sort方法获取一个Comparison,并相应地对列表进行排序。ForEach方法获取一个Action,并对每个元素执行特定行为。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 var films = new List<Film> { new Film {Name="Jaws", Year=1975}, new Film {Name="Singing in the Rain", Year=1952}, new Film {Name="Some like it Hot", Year=1959}, new Film {Name="The Wizard of Oz", Year=1939}, new Film {Name="It's a Wonderful Life", Year=1946}, new Film {Name="American Beauty", Year=1999}, new Film {Name="High Fidelity", Year=2000}, new Film {Name="The Usual Suspects", Year=1995} }; Action<Film> print = film => Console.WriteLine("Name={0}, Year={1}", film.Name, film.Year); // Note: extra lines added for clarity when running Console.WriteLine("All films"); films.ForEach(print); Console.WriteLine(); Console.WriteLine("Oldies"); films.FindAll(film => film.Year < 1960) .ForEach(print); Console.WriteLine(); Console.WriteLine("Sorted"); films.Sort((f1, f2) => f1.Name.CompareTo(f2.Name)); films.ForEach(print); Console.Read();
创建委托实例,用来打印列表中的项,因为之后会使用三次,所以用变量print来保存,而不用每次都单独使用一个Lambda表达式。它可以打印一个film类型,通过foreach就能打印整个列表。Action<Film> print = film => Console.WriteLine("Name={0}, Year={1}", film.Name, film.Year);
在事件处理程序中进行记录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 static void Log(string title, object sender, EventArgs e) { Console.WriteLine("Event: {0}", title); Console.WriteLine(" Sender: {0}", sender); Console.WriteLine(" Arguments: {0}", e.GetType()); foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(e)) { string name = prop.DisplayName; object value = prop.GetValue(e); Console.WriteLine(" {0}={1}", name, value); } } static void Main() { Button button = new Button(); button.Text = "Click me"; button.Click += (src, e) => Log("Click", src, e); button.KeyPress += (src, e) => Log("KeyPress", src, e); button.MouseClick += (src, e) => Log("MouseClick", src, e); Form form = new Form(); form.AutoSize = true; form.Controls.Add(button); Application.Run(form); }
表达式树 以编程方式构建表达式树,编译并执行 1 2 3 4 5 6 7 Expression firstArg = Expression.Constant(2); Expression secondArg = Expression.Constant(3); Expression add = Expression.Add(firstArg, secondArg); Func<int> compiled = Expression.Lambda<Func<int>>(add).Compile(); Console.WriteLine(compiled()); Console.Read();
将C# Lambda表达式转换成表达式树 1 2 3 Expression<Func<int>> return5 = () => 5; Func<int> compiled = return5.Compile(); Console.WriteLine(compiled());
()=》 5是Lambda表达式