2) Lambda表达式
前面提到在C#2.0中,我们用一个delegate关键字匿名地调用了一个委托方法,简化了程序员的工作,但同时我们也发觉程序的可读性降低了不少。下面我用一个例子来说明Lambda表达式是如何增强代码的可读性的。
还是以上面的UserInfo查询作为例子,下面的代码同样取出年龄在20-35之间的用户群。
var result1 = infoList.FindAll(p => (p.age > 20 && p.age < 35));这里仅仅只用了一行代码就完成了查询,是不是很神奇呢!我们来分析一下这句话的语义:首先是调用了infoList的FindAll方法,这个方法的原型如下:
// Summary:由于篇幅原因,我删掉一部分注解,大家可以注意到它的参数Predicate<T>毫无疑问是一个委托类型,这就证明了我们前面所说的Lambda表达式确实是一个委托的简化。接着在参数中第一个字母是p,指示了我们返回的数据,这里编译器可以通过前面infoList的类型判断出p的类型来。下面是指示符”=>”,表示返回的数据集合要符合后面的查询条件。
// Retrieves all the elements that match the conditions defined by the specified predicate.
//
// Parameters:
// match:
// The System.Predicate<T> delegate that defines the conditions of the elements
// to search for.
//
public List<T> FindAll(Predicate<T> match);
这里再举一个复杂一点的例子加以说明:
var groupBooksNumAndClicks =如果大家还有印象的话,这是我以前在介绍LINQ语言时写的一个数据库查询的例子,Tbl_books这张表包含了书籍的所有信息(书名,价格,等等),Tbl_types这张表包含了所有的书籍目录(比如数学类,计算机类等等), 我们要取出相同类别的书籍并计算每一类书籍总的点击量,有兴趣的朋友可以自行研究一下。
from book in books.Tbl_books
from type in books.Tbl_types
where book.Type_id == type.Id
group book by type.Name into g
select new { type = g.Key, booksSum = g.Count(), clicksSum = g.Sum(p => p.Clicks) };
3. 匿名方法机理
上面介绍了我们应当怎样使用匿名类型,下面我们通过阅读一些IL代码来看看编译器究竟为我们做了哪些工作。下面的代码演示了一个简单的匿名类型和匿名类型变量的调用,我们来看看编译器是怎么处理的。
namespace AnonymousTest很简单的一段代码,首先我们定义了一个UserInfo类,其中定义了一些属性,firstname,lastname等等,这里为了简单,我们直接使用公有变量,而不使用属性来表示了。接下来就是我们的Program类,在这个类中我们定义了集合变量,由于这里仅仅为了做演示,所以实际上我并没与往集合中添加成员,但已足够让CLR生成它的结构然后我们定义了result变量去取得它的检索结果,注意我们返回的是一个匿名类型。接着我们使用freach循环将其打印出来。
{
class UserInfo
{
public string firstname;
public string lastname;
public int age;
public string address;
//...
}
class Program
{
static void Main(string[] args)
{
List<UserInfo> infoList = new List<UserInfo>();
var result = from userinfo in infoList
where userinfo.age > 20 && userinfo.age < 35
select new { userinfo.firstname, userinfo.lastname };
foreach (var var_info in result)
{
Console.WriteLine(var_info.firstname + " " + var_info.lastname);
}
}
}
}