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];
//幹活
}