java多线程8:阻塞队列与Fork/Join框
827 2023-04-03 03:56:32
本文主要的是泛谈LINQ是啥?以及常见的用法大纲如下:
实际上,能够被foreach的对象,一定是实现了带有返回值的IEnumerator的GetEnumerator()方法的接口,而.NET内置的该接口则是IEnumerable,一般指的是IEnumerable
Copy public interface IEnumerator { object Current { get; } bool MoveNext(); void Reset(); }
因此,实际上我们进行foreach的时候,等价于:
Copyvar 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);}
输出结果:
CopyCatDogPig-----------CatDogPig
而能被LINQ的对象就是一个实现了IEnumerable的可被枚举的集合
LINQ的方法一般都是通过扩展方法了扩展的,就如最常用的几个,Where,Any,例如,我实现了一个跟Where功能类似的简化版:
Copy 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就是为了简单的能够处理复杂集合的数据,那么扩展方法就能够实现较为简单的链式查询,例如:
Copyvar result= animals.MyWhere(t => t is "Cat" or "Dog").Select(t=>t.ToUpper()).ToList();result.ForEach(t =>Console.WriteLine(t));
输出结果:
CopyCATDOG
假如上述的例子有LINQ的查询表达式来编写,则写法是这样:
Copyvar result = (from t in animals where t is "Cat" or "Dog" select t.ToUpper()).ToList();result.ForEach(t => Console.WriteLine(t));
输出结果也是一样的:
CopyCATDOG
首先我们来看看IQueryable的接口定义:
Copy public interface IQueryable : IEnumerable { Type ElementType { get; } Expression Expression { get; } IQueryProvider Provider { get; } }
我们可以看到实际上IQueryable
是继承了IEnumerable
,因此同样具备其特性,然后主要看其三个属性:
Copy public interface IQueryProvider { IQueryable CreateQuery(Expression expression); IQueryable<TElement> CreateQuery<TElement>(Expression expression); object? Execute(Expression expression); TResult Execute<TResult>(Expression expression); }
我们先来看段代码:
Copyvar 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);}
输出如下:
CopyExpression:System.Linq.Enumerable+WhereSelectListIterator`2[System.String,System.String]ExpressionType:System.Linq.Expressions.ConstantExpressionCATDOG---------------Expression:System.Linq.Enumerable+WhereSelectListIterator`2[System.String,System.String].Where(t => t.Contains("CAT"))ExpressionType:System.Linq.Expressions.MethodCallExpression2CAT
我们从输出可以证明,实际上在返回result1和result2,就是通过IQueryProvider
不断地在拼接表达式树,而最后通过foreach或者ToList等操作的时候,则才是真正调用Execute方法执行当前的IQueryable
里的那个表达式树属性Expression
,而像LINQ To Sql或者是EFCore等需要IQueryable
这种解释型的就是去实现了IQueryProvider
里面的方法