一、基本原理
2.用了拓展方法,在generic枚举类型来做,编译器会将LINQ语句解释为where上的枚举类型的事例对象上调用拓展方法 ,实现功能。因为拓展方法的拓展接口是IEnumerable所以所有继承该接口的实现类都支持该拓展方法。
不是所有的数据筛选都可以用预定义的拓展方法LINQ来表示,所以有时候要自己定义LINQ函数和拓展方法;拓展方法工作方式是直接from r in语句活得数据源结构对象集合调用where方法,返回结果集再调用select或者group方法;LINQ运算顺序都是从左到右的,如果嵌套的from语句那么外部和内部将有两个传入参数作为selectmany的输入,提供一个内部的类型作为约束,外部的类型输出和继续使用后面的约束。
3. 用了枚举器来做,LINQ只是定义遇到yield return标记返回不执行,foreach才执行yield return执行下去,转换为其它容器或ToLookup时候会立即执行 。但是注意中间数据结构元素的变化会迭代出不同的结果,如果最后用了Tolist等就不会等到迭代时才返回集合。
LINQ上的操作,where选定数据集,数据查找筛选,逻辑表达式和比较表达式支持,开始偏移和截取长度搜索个数,前面开始后面开始搜索,排序,分组,数据连接外部内部,集合操作,聚合函数,视图集合转换产生,判断是否满足条件的函数。
2).排序orderby语句,以及和 thenby多个组合语句。
3).分组group,group r by r.x into 别名 。是用groupby拓展方法来进行分组。
select new可以从分组的结果里面再创建新的统计结果。
4).连接jiont操作
5).集合操作交并差,可以将查询语句封装为方法或limban表达式.
二、LINQ数据处理应用
1).筛选from 嵌套from2).排序orderby语句,以及和 thenby多个组合语句。
3).分组group,group r by r.x into 别名 。是用groupby拓展方法来进行分组。
select new可以从分组的结果里面再创建新的统计结果。
4).连接jiont操作
5).集合操作交并差,可以将查询语句封装为方法或limban表达式.
6).zip(),take(),skip()方法。
7).聚合函数
8).转换为其它容器, 查询会在迭代时候执行,而转换为容器时候却会立即执行。
7).聚合函数
8).转换为其它容器, 查询会在迭代时候执行,而转换为容器时候却会立即执行。
ToLookup函数和非类型化的集合上使用LINQ就可以用Cast()方法作为转换。
9)Range,Empty,Repeat()不是拓展方法,而是集合类的正常静态方法,也会推迟执行,基于原来类型构建迭代器。
具体多查询资料和实践编程。
三、并行查询
在.net 4.0后增加的,通过System.Linq中的新类,ParallelEnumerable可以分解查询工作到多个线程中,ParallelEnumerable大多数拓展方法是ParallelQuery<TSource>的拓展,一个例外是AsParallel()方法它拓展了IEnumerable<TSource>接口,返回ParallelQuery<TSource>类,所以正常集合可以并行方式查询。
应用:1)正常查询用容器上containerName.AsParallel()方法,那么所有的where,select,sum都会变成Parallel版本的。
2)Partitioner.Create(containerName,true).AsParallel()来并行查询。
3)取消,调用WithCancellation方法,且传递一个CancellationToken作为令牌参数创建,需要调用时候用令牌Cancel()就可以了,例如:
例如:
static void Main()
{
// IntroParallel();
Cancellation();
}
static void Cancellation()
{
const int arraySize = 100000000;
var data = new int[arraySize];
var r = new Random();
for (int i = 0; i < arraySize; i++)
{
data[i] = r.Next(40);
}
var cts = new CancellationTokenSource();
new Thread(() =>
{
try
{
var sum = (from x in data.AsParallel().WithCancellation(cts.Token)
where x < 80
select x).Sum();
Console.WriteLine("query finished, sum: {0}", sum);
}
catch (OperationCanceledException ex)
{
Console.WriteLine(ex.Message);
}
}).Start();
Console.WriteLine("query started");
Console.Write("cancel? ");
int input = Console.Read();
if (input == 'Y' || input == 'y')
{
// cancel!
cts.Cancel();
}
}
static void IntroParallel()
{
const int arraySize = 100000000;
var data = new int[arraySize];
var r = new Random();
for (int i = 0; i < arraySize; i++)
{
data[i] = r.Next(40);
}
Stopwatch watch = new Stopwatch();
watch.Start();
var q1 = (from x in Partitioner.Create(data).AsParallel()
where x < 80
select x).Sum();
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
}
}
四、表达式树
表达式树是一个可以改变语义分析的编译器级别的功能,也就是可以为编写的不同的表达式语句,定义不同的执行函数。
通过树形结构来调用不同的处理函数。
例如:lambda表达式可以用于委托中,也可以用于Expression类型中作为参数,Expression有很多表达式的类型派生类,可以分析执行表达式,例如:
class Program
{
private static void DisplayTree(int indent, string message, Expression expression)
{
string output = String.Format("{0} {1} ! NodeType: {2}; Expr: {3} ",
"".PadLeft(indent, '>'), message, expression.NodeType, expression);
indent++;
switch (expression.NodeType)
{
case ExpressionType.Lambda:
Console.WriteLine(output);
LambdaExpression lambdaExpr = (LambdaExpression)expression;
foreach (var parameter in lambdaExpr.Parameters)
{
DisplayTree(indent, "Parameter", parameter);
}
DisplayTree(indent, "Body", lambdaExpr.Body);
break;
case ExpressionType.Constant:
ConstantExpression constExpr = (ConstantExpression)expression;
Console.WriteLine("{0} Const Value: {1}", output, constExpr.Value);
break;
case ExpressionType.Parameter:
ParameterExpression paramExpr = (ParameterExpression)expression;
Console.WriteLine("{0} Param Type: {1}", output, paramExpr.Type.Name);
break;
case ExpressionType.Equal:
case ExpressionType.AndAlso:
case ExpressionType.GreaterThan:
BinaryExpression binExpr = (BinaryExpression)expression;
if (binExpr.Method != null)
{
Console.WriteLine("{0} Method: {1}", output, binExpr.Method.Name);
}
else
{
Console.WriteLine(output);
}
DisplayTree(indent, "Left", binExpr.Left);
DisplayTree(indent, "Right", binExpr.Right);
break;
case ExpressionType.MemberAccess:
MemberExpression memberExpr = (MemberExpression)expression;
Console.WriteLine("{0} Member Name: {1}, Type: {2}", output,
memberExpr.Member.Name, memberExpr.Type.Name);
DisplayTree(indent, "Member Expr", memberExpr.Expression);
break;
default:
Console.WriteLine();
Console.WriteLine("{0} {1}", expression.NodeType, expression.Type.Name);
break;
}
}
static void Main()
{
Expression<Func<Racer, bool>> expression = r => r.Country == "Brazil" && r.Wins > 6;
DisplayTree(0, "Lambda", expression);
}
}
上述是lambda表达式用于Expression类型。
LINQ TO SQL中lambda表达式用于Expression<T>类型。
也可以定义自己的Expression<T>拓展方法类型和LINQ表达式,实现自己的表达式树,这样表达式树存在于程序集中,执行的时候会读取。
五、LINQ提供程序
LINQ语句.net框架中定义的目标对象有:LINQ to Objects, LINQ to XML,LINQ to SQL。
其中LINQ语句具体的解释由作用的数据源容器类型来决定。
例如LINQ to Objects中的Whered拓展方法定义为:
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource>s source, Func<TSource, bool> predicate);
LINQ to SQL中的where拓展方法定义为:
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource,bool>> predicate);
当在SQL中的where语句时候,因为作用的容器数据源类型是ADO中定义的ObjectContext类的CreateQuery<T>()方法返回一个实现了IQueryable<TSource>接口的ObjectQuery<T>对象,因此时候使用Queryable类的Where()方法。
LINQ 是比较深奥的主题,主要是用到了表达式树的函数式语言的编程思想,拓展方法拓展当前的数据源自定义拓展方法,数据源上进行数据的操作会创建各种类型的容器和需要的委托方法(lambda表达式),以及对各种数据源底层细节的封装对上层提供了统一的LINQ简易数据操作。