C#中的IEnumerable接口深入研究
C#和VB.NET中的LINQ提供了一种与SQL查询类似的“对象查询”语言,对于熟悉SQL语言的人来说除了可以提供类似关联、分组查询的功能外,还能获取编译时检查和Intellisense的支持,使用EntityFramework更是能够自动为对象实体的查询生成SQL语句,所以很受大中型信息系统设计者的青睐。
IEnumerable这个接口可以说是为了这个特性“量身定制”,再加上微软提供的扩展(Extension)方法和Lambda表达式,给开发者带来了无穷的便利。本人在最近的开发工作中使用了大量的这种特性,同时在调试过程中还遇到了一个小问题,那么正好趁此机会好好研究一下相关原理和实现。
先从一个现实的例子开始吧。假如我们要做一个商品检索功能(这只是一个例子,我当然不可能把公司的产品也业务在这里贴出来),其中有一个检索条件是可以指定厂家的名称并进行模糊匹配。厂家的包括两个名称:注册名称和一般性名称,我们只按一般性名称进行检索。当然你可以说直接用SQL查询就行了,但是我们的系统是以实体对象为核心进行设计的,厂家的数量也不会太多,大概1000条。为了不增加系统的复杂性,只考虑使用现有的数据访问层接口进行实现(按过滤条件获取商品,以及获取所有厂商),这时LINQ的便捷性就体现出来了。
借助IEnumerable接口和其辅助类,我们可以写出以下代码:
publicGoodsListResponseGetGoodsList(GoodsListRequestrequest) { //从数据库中按商品类别获取商品列表 IEnumerable<Goods>goods=GoodsInformation.GetGoodsByCategory(request.CategoryId);
//用户指定了商品名检索字段,进行模糊匹配 //如果没有指定,则不对商品名进行过滤 if(!String.IsNullOrWhiteSpace(request.GoodsName)) { request.GoodsName=request.GoodsName.Trim().ToUpper(); //按商品名对goods中的对象进行过滤 //生成一个新的IEnumerable<Goods>类型的迭代器 goods=goods.Where(g=>g.GoodsName.ToUpper().Contains(request.GoodsName)); }
//如果用户指定的厂商的检索字段,进行模糊匹配 if(!String.IsNullOrWhiteSpace(request.ManufactureName)) { request.ManufactureName=request.ManufactureName.Trim().ToUpper();
//只提供了获取所有厂商的列表方法 //取出所有厂商,筛选包含关键字的厂商 IEnumerable<Manufacture>manufactures=ManufactureInformation.GetAll(); manufactures=manufactures.Where(m=>m.Name.GeneralName.ToUpper() .Contains(request.ManufactureName));
//取出任何符合所匹配厂商的商品 goods=goods.Where(g=>manufactures.Any(m=>m.Id==g.ManufactureId)); }
GoodsListResponseresponse=newGoodsListResponse();
//将goods放到一个List<Goods>对象中,并返回给客户端 response.GoodsList=goods.ToList();
returnresponse; }