当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > LINQ学习笔记:Lambda表达式

ASP.NET
Asp.net 时间操作基类(支持短日期,长日期,时间差)
asp.net 获取机器硬件信息(cpu频率、磁盘可用空间、内存容量等)
asp.net 数据库备份还原(sqlserver+access)
Asp.Net 数据操作类(附通用数据基类)
Asp.net 弹出对话框基类(输出alet警告框)
Asp.net 文件上传类(取得文件后缀名,保存文件,加入文字水印)
Asp.net Socket客户端(远程发送和接收数据)
Asp.net 字符串操作基类(安全,替换,分解等)
Asp.Net数据输出到EXCEL表格中
asp.net Gridview里添加汇总行
asp.net UpdatePanel的简单用法
asp.net ajaxControlToolkit FilteredTextBoxExtender的简单用法
this connector is disabled错误的解决方法
sql事务应用积累
asp.net Page.Controls对象(找到所有服务器控件)
在asp.NET中字符串替换的五种方法
ASP.NET缓存方法分析和实践示例代码
asp.net 在DNN模块开发中遇到的resx怪问题
ASP.NET State service状态服务的问题解决方法
asp.net 结合mysql存储过程进行分页代码

ASP.NET 中的 LINQ学习笔记:Lambda表达式


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 90 ::
收藏到网摘: n/a

1. 查询操作链

为了构造更加复杂的查询, 我们可以增加而外的查询操作方法, 形成一个查询链. 例如下面的例子:

 1: string[] names = { "James","Jack","Harris"};
 2:  
 3: IEnumerable<string> query = names.Where(n => n.Contains ("a")).OrderBy (n => n.Length).Select (n => n.ToUpper( ));
 4:  
 5: foreach (string name in query)
 6: Console.Write (name + ","); //JACK,JAMES,HARRIS,

Where, OrderBy和Select都是标准的查询操作并且对应于Enumerable类中的扩展方法. Where会生成一个输入序列的过滤版本, OrderBy则生成一个输入序列的排序版本, Select方法生成一个新的序列, 此序列中的每个元素都是根据给定的lambda表达式进行了转换或者返回. 整个数据流程是从左到右, 因此数据将先被过滤, 然后排序, 最后才被返回.

一个查询操作不会去改变输入序列, 相反的, 它总是返回一个新的序列. 这点上LINQ受到了函数式编程的影响, 并且保持一致的风格.

当查询操作被串联在一起的时候, 每一个操作生成的输出序列将会被作为下一个操作的输入序列. 因此我们也可以使用另外一种渐进式的查询写法:

 1: var filtered = names.Where(n => n.Contains ("a"));
 2: var sorted = filtered.OrderBy(n => n.Length);
 3: var finalQuery = sorted.Select(n => n.ToUpper()); 

最终我们便利finalQuery得到的结果将会跟上面的例子是一样的:

 1: foreach (string name in finalQuery)
 2: Console.Write (name + ","); // JACK,JAMES,HARRIS,

2. 编写Lambda表达式

让我们看一下一个最简单的Lambda表达式,n => n.Contains(“a” ) , 在这个表达式中,输入类型是string, 输出类型是bool. 如果一个Lambda表达式返回一个bool值的话我们将它称为一个判定(predicate). Lambda表达式的目的是取决于特定的查询操作符. 例如如果是Where操作符的话, 它指示一个元素是否将会被包含在输出序列中. 而如果是OrderBy操作符的话, Lambda表达式将会把输入序列中的每一个元素映射到它的排序键上. 如果是Select操作符, Lambda表达式将决定输入序列中的每个元素在被放入输出序列之前应该如何转换. 在一个操作中包含的Lambda表达式总是应用于输入序列中的每一个单一元素, 而不是整个序列.

由于Lambda表达式是一个callback, 我们可以在其中放入我们自己的逻辑, 这令查询操作非常的强大, 并且简单. 我们可以看一下Enumerable.Where的实现, 忽略异常处理:

 1: public static IEnumerable<TSource> Where<TSource> (
 2: this IEnumerable<TSource> source,
 3: Func<TSource,bool> predicate)
 4: {
 5: foreach (TSource element in source)
 6: if (predicate (element))
 7: yield return element;
 8: }

2.1 Lambda表达式和Func标记

在标准的查询操作符中利用了范型Func代理, 它们存在于System.Linq中, 并且定义如下

Func中出现的参数顺序类型跟Lambda表达式中出现的一致. 因此, Func<TSource,bool>匹配一个TSource => bool的Lambda表达式, 它接受一个TSource类型的参数并且返回一个布尔值. 类似的, Func<TSource, TResult>匹配一个TSource => TResult的Lambda表达式. 以下是所有的Func代理定义(注意返回值的类型总是最后一个参数的类型):

delegate TResult Func <T> ( );

delegate TResult Func <T, TResult> (T arg1);

delegate TResult Func <T1, T2, TResult> (T1 arg1, T2 arg2);

delegate TResult Func <T1, T2, T3, TResult> (T1 arg1, T2 arg2, T3 arg3);

delegate TResult Func <T1, T2, T3, T4, TResult> (T1 arg1, T2 arg2, T3 arg3, T4 arg4);

2.2 Lambda表达式和元素命名

标准的查询操作使用以下的类型命名:

TSource: 输入序列中的元素类型

TResult: 输出序列中的元素类型 – 如果它是不同于TSource的话

TKey: 用于sorting, grouping, join中的key类型

TSource是由输入序列决定的, 而TResult和Tkey则由Lambda表示式来推断. 例如, 考虑以下的Select操作:

 1: static IEnumerable<TResult> Select<TSource,TResult> (
 2: this IEnumerable<TSource> source,
 3: Func<TSource,TResult> selector)

Func<TSource,TResult>匹配一个TSource=>TResult的Lambda表达式, 一个对应于输入元素, 另一个则对应于输出元素. TSource和TResult是不同的类型, 因此Lambda表达式可以更改每一个元素的类型. 更进一步, Lambda表达式决定了输出序列的类型. 例如:

 1: string[] names = { "James","Jack","Harris"};
 2: IEnumerable<int> query = names.Select (n => n.Length);
 3: foreach (int length in query)
 4: Console.Write (length); // 546

3. 自然排序

针对一个输入序列的排序功能在LINQ中是非常重要的. 一些操作符, 例如Take, Skip和Reverse都依赖于这个行为. Take操作符输出头x个元素, 而排除剩余的, Skip操作符则忽略了头x个元素, 输出所有余下的. Reverse操作符将一个序列中的元素进行反转.

4. 其他操作符

并非所有的操作都回返回一个序列, 针对于元素的操作符都只返回一个元素, 例如First, Last, Single, ElementAt等等:

 1: int[] myNumbers = { 7,6,5,4,3};
 2: int fn = myNumbers.First(); // 7
 3: Console.WriteLine(fn);
 4: int ln = myNumbers.Last(); // 3
 5: Console.WriteLine(ln);
 6: int sn = myNumbers.ElementAt(1); // 6
 7: Console.WriteLine(sn);

另外聚合操作符则返回一个单一值:

 1: int count = myNumbers.Count(); // 5;
 2: Console.WriteLine(count);
 3: int min = myNumbers.Min(); // 3;
 4: Console.WriteLine(min);

另外Contains,Any则返回bool值. 这些操作符并不返回一个集合, 因此他们不能在他们的结果集中再次调用其它的操作, 换句话说他们必须出现在整个查询链中的最后一个(或者是子查询.) 另外有些操作符接受两个输入序列, 例如Contact, 它将会将一个序列添加到另外一个当中去, 而Union类似, 区别是它会自动删除其中重复的元素. 待续!