網站首頁 編程語言 正文
前言
本文主要的是泛談LINQ是啥?以及常見的用法大綱如下:
- LINQ的那些根基
- LINQ的一些基本用法
LINQ的根基
IEnumerable和IEnumerator
為啥能夠被foreach?
實際上,能夠被foreach的對象,一定是實現了帶有返回值的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的對象就是一個實現了IEnumerable的可被枚舉的集合
LINQ的基本用法
擴展方法在LINQ的應用:LINQ的流式語法
LINQ的方法一般都是通過擴展方法了擴展的,就如最常用的幾個,Where,Any,例如,我實現了一個跟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就是為了簡單的能夠處理復雜集合的數據,那么擴展方法就能夠實現較為簡單的鏈式查詢,例如:
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的延遲執行:IQueryable
首先我們來看看IQueryable的接口定義:
public interface IQueryable : IEnumerable { Type ElementType { get; } Expression Expression { get; } IQueryProvider Provider { get; } }
我們可以看到實際上IQueryable是繼承了IEnumerable,因此同樣具備其特性,然后主要看其三個屬性:
- ElementType:集合的類型
- Expression:表達式樹,這是延遲執行的重點,下面我們會一窺究竟
- IQueryProvider:IQueryable創建表達式樹和執行的部分
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方法執行當前的IQueryable里的那個表達式樹屬性Expression,而像LINQ To Sql或者是EFCore等需要IQueryable這種解釋型的就是去實現了IQueryProvider里面的方法
附:將內存中對象轉換為 XML
LINQ 查詢可以輕松地在內存中數據結構、SQL 數據庫、ADO.NET 數據集和 XML 流或文檔之間轉換數據。 以下示例將內存中數據結構中的對象轉換為 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
總結
原文鏈接:https://www.cnblogs.com/ryzen/p/15674607.html
相關推薦
- 2022-07-01 Android?TextView跑馬燈實現原理及方法實例_Android
- 2022-06-10 redis?解決庫存并發問題實現數量控制_Redis
- 2022-04-06 關于Redis數據庫三種持久化方案介紹_Redis
- 2022-09-25 edge或谷歌瀏覽器打開默認是百度或其他,怎么修改成自己想要的頁面
- 2022-08-15 Docker常見用法
- 2022-12-13 Android之rk3588?開發環境準備及問題解決方法_Android
- 2023-03-16 iOS?schem與Universal?Link?調試時踩坑解決記錄_IOS
- 2023-02-09 Rust?所有權機制原理深入剖析_Rust語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支