表达式树

在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化。但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响。C# 3.0中出现的Lambda表达式在不牺牲可读性的前提下,进一步简化了委托。

LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态。这些操作表示了各种关于数据的逻辑,例如数据筛选,数据排序等等。通常这些操作都是用委托来表示。Lambda表达式是对LINQ数据操作的一种符合语言习惯的表示方式。

Lambda表达式不仅可以用来创建委托实例,C#编译器也能够将他们转换成表达式树。

下面我们就先看看Lambda表达式。

作为委托的Lambda表达式

Lambda表达式可以看作是C# 2.0的匿名方法的进一步演变,所以匿名方法能做的几乎一切事情都可以用Lambda表达式来完成(注意,匿名方法可以忽略参数,Lambda表达式不具备这个特性)。

跟匿名方法类似,Lambda表达式有特殊的转换规则:表达式的类型本身并非委托类型,但它可以通过隐式或显式的发那个是转换为一个委托实例。匿名函数这个术语同时涵盖了匿名方法和Lambda表达式。

下面看看使用Lambda表达式获得字符串长度的例子,通过Lambda将得到更见简洁、易读的代码:

static void Main(string[] args) { //使用C# 2.0中的匿名方法获取字符串长度 Func<string, int> strLength = delegate(string str) { return str.Length; }; Console.WriteLine(strLength("Hello World!")); //使用Lambda表达式 //(显式类型参数列表)=> {语句},lambda表达式最冗长版本 strLength = (string str) => { return str.Length; }; Console.WriteLine(strLength("Hello World!")); //单一表达式作为主体 //(显式类型参数列表)=> 表达式 strLength = (string str) => str.Length; Console.WriteLine(strLength("Hello World!")); //隐式类型的参数列表 //(隐式类型参数列表)=> 表达式 strLength = (str) => str.Length; Console.WriteLine(strLength("Hello World!")); //单一参数的快捷语法 //参数名 => 表达式 strLength = str => str.Length; Console.WriteLine(strLength("Hello World!")); }

"=>"是C# 3.0新增的,告诉编译器我们正在使用Lambda表达式。"=>"可以读作"goes to",所以例子中的Lambda表达式可以读作"str goes to str.Length"。从例子中还可以看到,根据Lambda使用的特殊情况,我们可以进一步简化Lambda表达式。

Lambda表达式大多数时候都是和一个返回非void的委托类型配合使用(例如Func<TResult>)。在C# 1.0中,委托一般用于事件,很少会返回什么结果。在LINQ中,委托通常被视为数据管道的一部分,接受输入并返回结果,或者判断某项是否符合当前的筛选器等等。

Lambda表达式本质

通过ILSpy查看上面的例子,可以发现Lambda表达式就是匿名方法,是编译器帮我们进行了转换工作,使我们可以直接使用Lambda表达式来进一步简化创建委托实例的代码。

表达式树

在List<T>中使用Lambda表达式

前面简单的介绍了什么是Lambda表达式,下面通过一个例子进一步了解Lambda表达式。

在前面的文章中,我们也提到了一下List<T>的方法,例如FindAll方法,参数是Predicate<T>类型的委托,返回结果是一个筛选后的新列表;Foreach方法获取一个Action<T>类型的委托,然后对每个元素设置行为。下面就看看在List<T>中使用Lambda表达式:

public class Book { public string Name { get; set; } public int Year { get; set; } } class Program { static void Main(string[] args) { var books = new List<Book> { new Book{Name="C# learning guide",Year=2005}, new Book{Name="C# step by step",Year=2005}, new Book{Name="Java learning guide",Year=2004}, new Book{Name="Java step by step",Year=2004}, new Book{Name="Python learning guide",Year=2003}, new Book{Name="C# in depth",Year=2012}, new Book{Name="Java in depth",Year=2014}, new Book{Name="Python in depth",Year=2013}, }; //创建一个委托实例来表示一个通用的操作 Action<Book> printer = book => Console.WriteLine("Name = {0}, Year = {1}", book.Name, book.Year); books.ForEach(printer); //使用Lambda表达式对List<T>进行筛选 books.FindAll(book => book.Year > 2010).ForEach(printer); books.FindAll(book => book.Name.Contains("C#")).ForEach(printer); //使用Lambda表达式对List<T>进行排序 books.Sort((book1, book2) => book1.Name.CompareTo(book2.Name)); books.ForEach(printer); Console.Read(); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/cec5f5d4b02d3e171ee2002e4b687d72.html