帶你一文了解C#中的LINQ
前言
本文主要的是泛談LINQ是啥?以及常見的用法大綱如下:
- LINQ的那些根基
- LINQ的一些基本用法
LINQ的根基
IEnumerable和IEnumerator
為啥能夠被foreach?
實際上,能夠被foreach的對象,一定是實現(xiàn)了帶有返回值的IEnumerator的GetEnumerator()方法的接口,而.NET內置的該接口則是IEnumerable,一般指的是IEnumerable泛型接口,讓我們來看看IEnumerator接口有啥成員:
public interface IEnumerator
{
object Current
{
get;
}
bool MoveNext();
void Reset();
}
- Current:集合當前的對象
- MoveNext:是否能夠移動到下一次
- Reset
因此,實際上我們進行foreach的時候,等價于:
var animals = new List<string>() { "Cat", "Dog", "Pig" };
foreach (var animla in animals)
{
Console.WriteLine(animla);
}
Console.WriteLine("-----------");
var enumerator = animals.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}
輸出結果:
Cat
Dog
Pig
-----------
Cat
Dog
Pig
而能被LINQ的對象就是一個實現(xiàn)了IEnumerable的可被枚舉的集合
LINQ的基本用法
擴展方法在LINQ的應用:LINQ的流式語法
LINQ的方法一般都是通過擴展方法了擴展的,就如最常用的幾個,Where,Any,例如,我實現(xiàn)了一個跟Where功能類似的簡化版:
public static class MyListExtension
{
public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> enumable, Func<T, bool> func)
{
foreach (var item in enumable)
{
if (func(item))
{
yield return item;
}
}
}
}
其實為啥會提到用擴展方法呢?就是因為LINQ就是為了簡單的能夠處理復雜集合的數(shù)據,那么擴展方法就能夠實現(xiàn)較為簡單的鏈式查詢,例如:
var result= animals.MyWhere(t => t is "Cat" or "Dog").Select(t=>t.ToUpper()).ToList(); result.ForEach(t =>Console.WriteLine(t));
輸出結果:
CAT
DOG
LINQ的查詢表達式:LINQ的查詢語法
假如上述的例子有LINQ的查詢表達式來編寫,則寫法是這樣:
var result = (from t in animals
where t is "Cat" or "Dog"
select t.ToUpper()).ToList();
result.ForEach(t => Console.WriteLine(t));
輸出結果也是一樣的:
CAT
DOG
LINQ的延遲執(zhí)行:IQueryable
首先我們來看看IQueryable的接口定義:
public interface IQueryable : IEnumerable
{
Type ElementType
{
get;
}
Expression Expression
{
get;
}
IQueryProvider Provider
{
get;
}
}
我們可以看到實際上IQueryable是繼承了IEnumerable,因此同樣具備其特性,然后主要看其三個屬性:
- ElementType:集合的類型
- Expression:表達式樹,這是延遲執(zhí)行的重點,下面我們會一窺究竟
- IQueryProvider:IQueryable創(chuàng)建表達式樹和執(zhí)行的部分
public interface IQueryProvider
{
IQueryable CreateQuery(Expression expression);
IQueryable<TElement> CreateQuery<TElement>(Expression expression);
object? Execute(Expression expression);
TResult Execute<TResult>(Expression expression);
}
我們先來看段代碼:
var result1 = (from t in animals
where (t.Equals( "Cat") || t.Equals("Dog"))
select t.ToUpper()).AsQueryable();
Console.WriteLine($"Expression:{ result1.Expression.ToString()}");
Console.WriteLine($"ExpressionType:{result1.Expression.GetType()}");
foreach (var item in result1)
{
Console.WriteLine(item);
}
Console.WriteLine("---------------");
var result2 = from t in result1
where t.Contains("CAT")
select t;
Console.WriteLine($"Expression:{ result2.Expression.ToString()}");
Console.WriteLine($"ExpressionType:{result2.Expression.GetType()}");
foreach (var item in result2)
{
Console.WriteLine(item);
}
輸出如下:
Expression:System.Linq.Enumerable+WhereSelectListIterator`2[System.String,System.String]
ExpressionType:System.Linq.Expressions.ConstantExpression
CAT
DOG
---------------
Expression:System.Linq.Enumerable+WhereSelectListIterator`2[System.String,System.String].Where(t => t.Contains("CAT"))
ExpressionType:System.Linq.Expressions.MethodCallExpression2
CAT
我們從輸出可以證明,實際上在返回result1和result2,就是通過IQueryProvider不斷地在拼接表達式樹,而最后通過foreach或者ToList等操作的時候,則才是真正調用Execute方法執(zhí)行當前的IQueryable里的那個表達式樹屬性Expression,而像LINQ To Sql或者是EFCore等需要IQueryable這種解釋型的就是去實現(xiàn)了IQueryProvider里面的方法
附:將內存中對象轉換為 XML
LINQ 查詢可以輕松地在內存中數(shù)據結構、SQL 數(shù)據庫、ADO.NET 數(shù)據集和 XML 流或文檔之間轉換數(shù)據。 以下示例將內存中數(shù)據結構中的對象轉換為 XML 元素。
class XMLTransform
{
static void Main()
{
// Create the data source by using a collection initializer.
// The Student class was defined previously in this topic.
List<Student> students = new List<Student>()
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores = new List<int>{97, 92, 81, 60}},
new Student {First="Claire", Last="O'Donnell", ID=112, Scores = new List<int>{75, 84, 91, 39}},
new Student {First="Sven", Last="Mortensen", ID=113, Scores = new List<int>{88, 94, 65, 91}},
};
// Create the query.
var studentsToXML = new XElement("Root",
from student in students
let scores = string.Join(",", student.Scores)
select new XElement("student",
new XElement("First", student.First),
new XElement("Last", student.Last),
new XElement("Scores", scores)
) // end "student"
); // end "Root"
// Execute the query.
Console.WriteLine(studentsToXML);
// Keep the console open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
此代碼生成以下 XML 輸出:
<Root>
<student>
<First>Svetlana</First>
<Last>Omelchenko</Last>
<Scores>97,92,81,60</Scores>
</student>
<student>
<First>Claire</First>
<Last>O'Donnell</Last>
<Scores>75,84,91,39</Scores>
</student>
<student>
<First>Sven</First>
<Last>Mortensen</Last>
<Scores>88,94,65,91</Scores>
</student>
</Root>
參考
《C#7.0核心技術指南》
源碼
BlogCodeSample/LinqSample at main · ZhengDaoWang/BlogCodeSample
總結
到此這篇關于C#中LINQ的文章就介紹到這了,更多相關C#的LINQ內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C#中使用強制類型實現(xiàn)字符串和ASCII碼之間的轉換
這篇文章主要介紹了C#中使用強制類型實現(xiàn)字符串和ASCII碼之間的轉換,本文還給出了另一種方法,需要的朋友可以參考下2014-08-08
C#應用XML作為數(shù)據庫的快速開發(fā)框架實現(xiàn)方法
這篇文章主要介紹了C#應用XML作為數(shù)據庫的快速開發(fā)框架實現(xiàn)方法,詳細介紹了將XML作為數(shù)據庫的C#桌面應用開發(fā)技巧,具有一定的參考借鑒價值,需要的朋友可以參考下2014-12-12
C#用websocket實現(xiàn)簡易聊天功能(服務端)
這篇文章主要為大家詳細介紹了C#用websocket實現(xiàn)簡易聊天功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02

