LINQ使用(一)
一、什么是LINQ
LINQ即 Language Integrated Query,语言集成查询,是微软新增的一种类似SQL查询数据库的方式的自然查询方法,是.net框架的扩展,查询时数据集时,非常方便,不用使用for/foreach循环遍历了。
大约有40多个关键字帮助查询。
Where、Select、SelectMany、Skip、SkipWhile、Take、TakeWhile、Join、GroupJoin、Concate、OrderBy、OrderByDescending、ThenBy、ThenByDescending、Reverse、GroupBy、Distinct、Union、Intersect、Except、AsEnumerable、AsQueryable、ToArray、ToList、ToDictionary、ToLookup、OfType、Cast、SequenceEqual、First、FirstOrDefault、Last、LastOrDefault、Single、SingleOrDefault、ElementAt、ElementAtOrDefault、DefaultIfEmpty、All、Any、Contains、Count、LongCount、Sum、Min、Max、Average、Aggregate、equals/Equals、from/From、in/In、into/Into、key、let、Group、Range、Repeat。
二、如何使用LINQ
有两种方式,第一种,可以像SQL语句一样查询,也可以使用方法调用的方式查询。
// LINQ Query
//Method 1:
var bmws = from Car in MyCars
where Car.Make == "BMW"
select Car;
//Method 2:
var bmws2 = MyCars.Where(p => p.Make == "BMW" && p.Year == 2018);
第二种p=>p.Make使用了lamda表达式,使语句更加简洁。
举个栗子:
- 定义1个Car类 class Car;
- 创建1个Car类的集合 List MyCars = new List();
- 通过LINQ进行查询、排序、判断、和输出。
以下是一些例子,可模仿一下。
class Program
{
class Car
{
public string Make;
public int Year;
}
static void Main(string[] args)
{
List<Car> MyCars = new List<Car>();
MyCars.Add(new Car() { Make = "BMW", Year = 2018 });
MyCars.Add(new Car() { Make = "ZhongHua", Year = 2019 });
MyCars.Add(new Car() { Make = "BMW", Year = 2019 });
MyCars.Add(new Car() { Make = "BYD", Year = 2018 });
MyCars.Add(new Car() { Make = "HongQi", Year = 2017 });
// LINQ Query
var bmws = from Car in MyCars
where Car.Make == "BMW"
select Car;
var bmws2 = MyCars.Where(p => p.Make == "BMW" && p.Year == 2018);
//SORT
var orderedCars = from Car in MyCars
orderby Car.Year descending
select Car;
var orderedCars2 = MyCars.OrderByDescending(p => p.Year);
//choose first pick
var firstCar = MyCars.First(p => p.Make == "BMW");
//Order then choose the first
var firstBMW = MyCars.OrderByDescending(p => p.Year).First(p => p.Make == "BMW");
//print
Console.WriteLine(MyCars.TrueForAll(p => p.Year > 2012)); //True
MyCars.ForEach(p => Console.WriteLine("{0}{1:c}", p.Make, p.Year)); // BMW ¥2018.00...
Console.WriteLine(MyCars.Exists(p => p.Make == "DaZhong")); //false
Console.WriteLine(MyCars.GetType()); // System.Collections.Generic.List`1[LINQ_Test.Program+Car]
//caculate
MyCars.ForEach(p => p.Year += 1);
var newCars = from Car in MyCars
where Car.Make == "BMW"
&& Car.Year == 2018
select new { Car.Make, Car.Year };
}
}
三、个人使用爱好
- Where中判断语句传入函数
LINQ中Where语句,可以看出来,里面其实是一个bool类型的判断,返回true or false。
所以,使用时不必拘泥与对数据集成员本身的判断,骚操作是写入一个返回值为bool类型的函数,函数其中1个参数为数据集成员,如下所示,CheckHiddenPoint§函数就是对数据集对象进行处理,但是返回值为bool类型的,如此就可以避免采用for循环进行遍历了。
var checkEnts = listHiddenEntEx.AsParallel().Where(p =>CheckHiddenPoint(p)).ToList();
- 可以看到,linq支持并行处理,即多个成员同时进行判断处理,添加关键字.AsParallel.
//串行处理,1个接1个
var checkEnts = listHiddenEntEx.Where(p =>CheckHiddenPoint(p)).ToList();
//并行处理,加快处理速度。
var checkEnts = listHiddenEntEx.AsParallel().Where(p =>CheckHiddenPoint(p)).ToList();
- 使用并行计算时,如果要向同一个List集合中添加数据时,会造成两条数据同时向List中同一位置写入数据,会有资源争抢问题,会报访问index错误,并且并行过程中不可对写入的数据集进行Clear()操作,也会发生访问Index错误。未防止错误发生,可去掉并行处理。
一般不建议写入数据集过程中还要清理数据集的操作,会引发混乱。
如果单纯想并行写入同一个数据集,可采用lock的方法锁定数据集,每次只允许1个数据集写入数据。即可保证访问Index的正确性。
特别强调:并行计算可以节约时间,但是加锁会减缓时间,让众多线程等待1个线程完成操作之后才能处理,所以到底是节约了时间没有,值得思考。
dic.AsParallel.Alll(p=>{AddRecord(p.Key,p.Value); return true;})
//声明公共数据集
List<string>() errorRecords = new List<string>();
public bool AddRecord(string A, string B){
//干活
lock (errorRecords)
{
errorRecords.Add("发生错误"});
}
}
-
两个数据集进行判断,采用SQL语句写。listWWTPEnt 与 listInAreaEnt 为2个List数据集,写2次from,即可以对两个数据集成员同时判断。
该方法等效于for循环2次。
var listWSandPFK = from wwtp in listWWTPEnt
from inarea in listInAreaEnt
where isPfkInPsInArea(inarea, wwtp)
select new { inarea, wwtp };
foreach (var item in listWSandPFK)
{
//干活
}
//等效于for循环2次
for (int i = 0; i < listInAreaEnt.Count; i++)
{
for (int j = 0; j < listPKEnt.Count; j++)
{
if (isPfkInPsInArea(listInAreaEnt[i], listPKEnt[j]))
{
//干活
}
}
}
- 分组处理。有时候1个数据集需要根据成员属性进行分组,使用GroupBy关键字。
List<CommDB.CCommStruct.CheckCondition> listCheckCondition;
//干活
//按 应用图层和几何类型分组
var checkGroups = listCheckCondition.GroupBy(p => new { p.yycm, p.jhlx }).ToList();
for (int i = 0; i < checkGroups.Count; i++) //group.Key 为应用图层名
{
string layer = checkGroups[i].Key.yycm;
string geoType = checkGroups[i].Key.jhlx
List<CommDB.CCommStruct.CheckCondition> newGroupi = checkGroups[i];
//干活
}