网站开发客户来源,广东省建设厅网站可以查,网页html模板代码,室内设计联盟网页版此文章非原创,转载自诗人江湖老,原文地址 在Git上下载源码 在工程中我们少不了要定义类或者结构去储存数据#xff0c;这些数据将被临时地储存在内存中#xff0c;现在我们想要对其完成一些类似于查找、过滤等等常见的任务的时候#xff0c;我们该如何去做呢#xff1…此文章非原创,转载自诗人江湖老,原文地址 在Git上下载源码 在工程中我们少不了要定义类或者结构去储存数据这些数据将被临时地储存在内存中现在我们想要对其完成一些类似于查找、过滤等等常见的任务的时候我们该如何去做呢 我们可以自己写代码去对集合中的每个对象进行遍历检查变量的每个字段看其是否满足条件。这样的故事已经发生太多次了微软怎么可能容忍在C#里发生如此弱智的事情呢于是C#的设计者决定在C#中集成查询的语法以最大限度地减少程序员书写类似代码的情况。 这也就是我们说的LINQ(Language Intergated Query)也就是语言集成查询我们可以使用同样的语法访问不同的数据源。
为什么要使用LINQ 几乎所有的应用程序都需要对数据进行处理大部分的程序都通过自定义的逻辑来完成这些操作。这样做的弊端之意就是代码逻辑将会跟它处理的数据的结构紧密耦合在一起如果数据结构发生了改变也许将会带来海量的代码改动。 为了解决这个问题C#将这些处理数据的代码都抽象出来提供给了广大开发者。这就是LINQ。 LINQ的语法类似于关系和分层查询语言(SQL和XQuery)我们可以在不更改查询代码的情况下对数据结构进行更改。LINQ比之SQL要更加灵活可以处理更广泛的逻辑数据结构。当然这些数据结构都需要实现了IEnumerable或者IEnumerable T 接口才可以进行LINQ查询。
LINQ查询表达式语法详解
表达式基础语法 LINQ查询表达式以from子句开始以select或者group子句结束。在这两个子句之间可以跟零个或者多个from、let、where、join或者orderby子句。 每个from子句都是一个生成器该生成器将引入一个包括序列(Sequence)的元素的范围变量(range variable)。每个let子句都会引入一个范围变量以表示通过前一个范围变量计算的值。每个where子句都是一个筛选器用于从结果中排除项。每个join子句都将指定的源序列键与其他序列的键进行比较以产生匹配对。每个orderby子句都会根据指定的条件对各项进行重新排序。而最后的select或者group子句根据范围变量来指定结果的表现形式。最后可以使用into子句来连接查询将某一查询结果的视为后续查询的生成器。
标准查询操作符 在了解LINQ查询表达式之前怎么能不了解下它的查询操作符呢下面列表列出了LINQ定义的标准查询操作符。
表1:LINQ标准查询操作符标准查询操作符说明where OfTypeTResult筛选操作符定义了返回元素的条件。在Where查询操作符中可以使用谓词例如Lambda表达式定义的谓词来返回布尔值。OfTypeTResult根据类型筛选元素只返回TResult的类型元素Select 和SelectMany投射操作符用于把对象转换为另一个类型的新对象。Select和SelectMany定义了根据选择器函数选择结果值的投射。OrderBy、ThenBy 、OrderByDescending 、ThenByDescending 、Reverse排序操作符改变所返回的元素的顺序。OrderBy按升序排列OrderByDescending按降序排列。如果第一次排序结果很类似就可以使用ThenBy和ThenByDescending操作符进行第二次排序。Reverse反转集合中的元素顺序。GroupBy、ToLookUp组合运算符把数据放在组里面。GroupBy操作符组合有公共键的元素。ToLookUp通过创建一个一对多的字典来组合元素。Join、GroupJoin链接运算符用于合并不直接相关的集合。使用Join操作符可以根绝键选择器函数连接两个集合这类似于SQL中的Join。GroupJoin操作符连接两个集合组合其结果。Any、All、Contains如果元素序列满足指定的条件两次操作符就返回布尔值。Any、ALll和Contains都是限定符操作符。Any确定集合中是否有确定满足谓词函数的元素。ALll确定集合中的所有元素是否都满足谓词函数。Contains检查某个元素是否在集合中。这些操作符都返回一个布尔值。Take、Skip、TakeWhile、SkipWhile分区操作符返回集合的一个子集Take、Skip、TakeWhile、SkipWhile都是分区操作符。使用它们可以得到部分结果使用Take必须指定要从集合中提取的元素个数Skip跳过指定个数的元素提取其它元素TakeWhile提取条件为真的元素。Distinct、Union、Intersect、Except、ZipSet操作符返回一个集合。Distinct从集合中删除重复的元素除了Distinct之外其它的Set操作符都需要两个集合。Union返回出现在其中一个集合中的唯一元素。Intersect返回两个集合中都有的元素。Except返回值出现在一个集合中的元素。Zip是.NET 4新增的它把两个集合合并为一个。First、FirstOrDefault、Last、LastOrDefault、ElementAt、ElementAtOrDefault、Single、SingleOrDefault这些元素操作符仅返回一个元素。First返回第一个满足条件的元素。FirstOrDefault类似于First单如果没有找到满足条件的元素就返回类型的默认值。Last返回最后一个满足条件的元素。ElementAt指定了要返回的元素的位置。Single只返回一个满足条件的元素。如果有多个元素都满足条件就抛出一个异常。Count、Sum、Min、Max、Average、Aggregate聚合操作符计算集合的一个值。利用这些聚合操作符可以计算所有值的总和、所有元素的个数、值最大和最小的元素以及平均值等等。ToArray、ToEnumerable、ToList、ToDictionary、CastTRsult这些转换操作符将集合转换为数组IEnumerable、IList、IDictionary等。Empty、Range、Repeat这些生成操作符返回一个心机和。使用Empty时集合是空的Range返回一系列数字Repeat返回一个始终重复一个值的集合。设置案例背景 假设我们有4个类CustomerOrderDetailProduct它们的定义如下
Customer类字段字段类型CustomerIDintCountrystringNamestringCitystringOrdersListOrderOrder类字段字段类型OrderIDintCustomerIDintTotalintOrderDateDateTimeDetailsListDetailDetail类字段字段类型DetailIDintOrderIDintUnitPricedoubleQuantitydoubleProductIDintProduct类字段字段类型ProductIDintProductNamestring假设现在它们各自有一个List集合分别为CustomersOrdersDetailsProducts。我们在这基础之上来一步步阐述LINQ查询表达式。 customers数据
CustomerIDCityCountryNameOrders0北京中国小米orders.FindAll(c c.CustomerID 0)1首尔韩国三星orders.FindAll(c c.CustomerID 1)2加州美国苹果orders.FindAll(c c.CustomerID 2)3台北中国HTCorders.FindAll(c c.CustomerID 3)4珠海中国魅族orders.FindAll(c c.CustomerID 4)5北京中国华为orders.FindAll(c c.CustomerID 5)6上海中国索尼orders.FindAll(c c.CustomerID 6)7北京中国联想orders.FindAll(c c.CustomerID 7)8上海中国诺基亚orders.FindAll(c c.CustomerID 8)orders数据
OrderIDCustomerIDOrderDateDetails00DateTime.Nowdetails.FindAll(d d.OrderID 0)10DateTime.Nowdetails.FindAll(d d.OrderID 1)21DateTime.Nowdetails.FindAll(d d.OrderID 2)31DateTime.Nowdetails.FindAll(d d.OrderID 3)42DateTime.Nowdetails.FindAll(d d.OrderID 4)52DateTime.Nowdetails.FindAll(d d.OrderID 5)63DateTime.Nowdetails.FindAll(d d.OrderID 6)73DateTime.Nowdetails.FindAll(d d.OrderID 7)84DateTime.Nowdetails.FindAll(d d.OrderID 8)95DateTime.Nowdetails.FindAll(d d.OrderID 9)106DateTime.Nowdetails.FindAll(d d.OrderID 10)116DateTime.Nowdetails.FindAll(d d.OrderID 11)127DateTime.Nowdetails.FindAll(d d.OrderID 12)137DateTime.Nowdetails.FindAll(d d.OrderID 13)148DateTime.Nowdetails.FindAll(d d.OrderID 14)158DateTime.Nowdetails.FindAll(d d.OrderID 15)168DateTime.Nowdetails.FindAll(d d.OrderID 16)details数据
DetailIDOrderIDProductIDQuantityUnitPrice0001000101112134822112369330754744223541255069851366242131077319771088228769959778121010485411111127561012123100091313178681414334671515257661616078210products数据
ProductIDProductName0samsung1nokia2apple3xiaomi4huawei5lenovoDemo查询表达式
条件筛选 使用where子句可以按照一个或者多个条件筛选集合where子句的表达式的结果类型应该是布尔类型。 筛选在北京且名称以‘小’开头的顾客。
var query from c in customerswhere c.City 北京 c.Name.StartsWith(小)select c;
foreach (Customer item in query)
{Console.WriteLine(item.Name \t\t item.City);
}
Console.ReadKey(); 该LINQ查询会返回在北京而且名字以“小”开头的Customer集合。 输出结果
复合from子句筛选 当需要根绝对象的一个成员进行筛选而该成员本身是一个集合或者列表就可以使用复合的from子句。 筛选订单数量大于800的信息。
var query from c in customersfrom o in c.Ordersfrom d in o.Detailswhere d.Quantity 800select new { Name c.Name, Total d.UnitPrice * d.Quantity };foreach (var item in query)
{Console.WriteLine(item.Name \t\t item.Total);
}
Console.ReadKey(); 输出结果
排序 要对序列排序需要使用orderby子句。 按照城市、顾客ID进行排序。
var query from c in customersfrom o in c.Ordersorderby c.City, o.CustomerIDselect new { Name c.Name, City c.City, OrderID o.OrderID };foreach (var item in query)
{Console.WriteLine(item.Name \t\t item.City \t\t item.OrderID);
}
Console.ReadKey(); 输出结果
分组 要根木一个关键值对查询结果分组可以使用group子句。 统计各个产品的订单数量。
var query from d in detailsgroup d by d.ProductID into gorderby g.Count(), g.Keyselect new { Name g.Key, Count g.Count() };
Console.WriteLine(ProductID \t Count);
foreach (var item in query)
{Console.WriteLine(item.Name \t\t item.Count);
}
Console.ReadKey(); 输出结果
对嵌套的对象分组 如果分组的对象包含嵌套的序列则各个改变select子句创建的匿名类型。 统计各个产品的订单数量并输出各个订单的订货数量。
var query from d in detailsgroup d by d.ProductID into gorderby g.Count(), g.Keyselect new{Name g.Key,Count g.Count(),Quantity from d in gorderby d.Quantityselect d.Quantity};Console.WriteLine(ProductID\tCount\tQuantity);
foreach (var item in query)
{Console.Write(item.Name \t\t item.Count\t);foreach (var quantity in item.Quantity){Console.Write({0};, quantity);}Console.WriteLine();
}
Console.ReadKey(); 输出结果
连接 使用join子句可以根据特定的条件合并两个数据源但之前要获得两个要连接的列表。 统计各个顾客和其订单的信息。
var query from r infrom c in customersfrom o in c.Ordersfrom d in o.Detailsselect new { Name c.Name, City c.City, Money d.Quantity * d.UnitPrice, ProductID d.ProductID }join t infrom p in productsselect pon r.ProductID equals t.ProductIDselect new { Name r.Name, City r.City, Money r.Money, ProductName t.ProductName };
Console.WriteLine(Name \t City \t Money \t ProductName);
foreach (var item in query)
{Console.WriteLine(item.Name \t item.City \t item.Money \t item.ProductName);
}
Console.ReadKey(); 输出结果
聚合操作符 聚合操作符包括Count()、Sum()、Min()、Max()、Average()和Aggregate()它们不返回一个序列而是返回一个值。 Count()方法返回集合中的项数Sum()方法汇总序列中所有数字返回这些数字的和Min()方法返回集合中的最小值Max()方法返回集合中的最大值Average()方法计算集合中的平均值Aggregate()方法可以传递一个Lambda表达式该表达式对所有的值进行聚合。 这些方法的使用方式类似都是直接对序列或者集合进行操作。下面用Sum()做一个示例 统计各个顾客总共订单的订货数量。
var query from r infrom c in customersselect new{Name c.Name,OrderCount ( from o in c.Ordersfrom d in o.Detailsselect d.Quantity).Sum()}orderby r.OrderCountselect r; 输出结果
使用扩展方法和Lambda表达式简化LINQ查询
什么是扩展方法 当方法的第一个形参包含this修饰符的时候该方法称为扩展方法。扩展方法只能在非泛型、非嵌套的静态类中声明扩展方法的第一个形参不能带有除this之外的其他任何修饰符而且形参类型不能是指针类型。 下面的程序是一个扩展方法的示例
public static class Extensions
{public static void HelloWorld(this string str){Console.WriteLine({0} 调用了HellWorld,str);}
} 现在就可以调用该方法了:
string strJay;
str.HelloWorld(); 我们可以看到控制台中输出了“Jay 调用了HelloWorld”。 之所以这样是因为HelloWorld第一个参数类型为string类型因此该方法就是string类型的扩展方法所有的string类型变量都可以调用而变量的内容就是传递给HelloWorld的参数。 上面的程序和下面的代码结果一样
string str Jay;
Extensions.HelloWorld(str);
LINQ扩展方法 LINQ为IEnumerableT接口提供了各种扩展方法以便用户在实现了该接口的任意集合上使用LINQ查询。表1中列出的LINQ查询操作符都有相应的扩展方法实现。 使用扩展方法可以和使用LINQ查询表达式获得十分类似甚至是相同的结果当扩展方法和Lambda表达式结合的时候会大大简化LINQ查询。
简化LINQ查询 前面一节的条件筛选LINQ表达式可以简化为
var query customers.Where(c c.City 北京 c.Name.StartsWith(小)).Select(c c);1 前面一节的条件复合from子句筛选LINQ表达式可以简化为
var query customers.SelectMany(c c.Orders, (c, o) new { _customer c, _order o, _detail o.Details }).SelectMany(a a._detail, (a, b) new { _var a, Total b.Quantity * b.UnitPrice, Quantity b.Quantity }).Where(_nameless _nameless.Quantity 800).Select(_annonymous new { Name _annonymous._var._customer.Name, Total _annonymous.Total });1 前面一节的排序LINQ表达式可以简化为
var query customers.SelectMany(c c.Orders, (c, o) new { _customer c, _order o }).OrderBy(_var _var._customer.City).ThenBy(_var _var._order.CustomerID).Select(_annonymous new { Name _annonymous._customer.Name, City _annonymous._customer.City, OrderID _annonymous._order.OrderID });1 前面一节的分组LINQ表达式可以简化为
var query details.GroupBy(d d.ProductID).OrderBy(g g.Count()).ThenBy(g g.Key).Select(g new { Name g.Key, Count g.Count() });1 前面一节的对嵌套的对象分组LINQ表达式可以简化为
var query details.GroupBy(d d.ProductID).OrderBy(g g.Count()).ThenBy(g g.Key).Select(_var new { Name _var.Key, Count _var.Count(), Quantity _var.OrderBy(d d.Quantity).Select(d d.Quantity) });1 前面一节的连接LINQ表达式可以简化为
var query customers.SelectMany(c c.Orders, (c, o) new { Name c.Name, City c.City, Details o.Details }).SelectMany(_var _var.Details, (_var, _detail) new { Name _var.Name, City _var.City, Money _detail.Quantity * _detail.UnitPrice, ProductID _detail.ProductID }).Join(products, a a.ProductID, b b.ProductID, (a, b) new { Name a.Name, City a.City, Money a.Money, ProductName b.ProductName });1 前面一节的聚合操作LINQ表达式可以简化为
var query customers.Select(c new { Name c.Name, OrderCount c.Orders.SelectMany(o o.Details, (o, d) new { _Quantity d.Quantity }).Select(_var _var._Quantity).Sum() }).OrderBy(_var _var.OrderCount);1 以上利用扩展方法和Lambda表达式的简化后的LINQ查询代码的查询结果与LINQ查询表达式结果完全一样证明这样是完全可行的。 唯一的问题就是代码看起来比较费解了。
LINQ查询表达式简化转换原则 看到这里我们可能要奇怪为什么我们能用这样的方式来简化LINQ查询表达式呢 关于这个问题我们将在下一篇文章进行详细讲解。 欢迎大家点击阅读。 本人还是菜鸟写的不对的地方还请各位不吝赐教