(六)LINQ

LINQ

语言集成查询,提供了一个抽象层,类似SQL语法,允许不同数据源的查询使用相同的语法。

linq以扩展方法方式实现,扩展了IEnumerable<out T>接口,使用时需要使用System.Linq命名空间,在System.Linq.Enumerable定义了where、select等方法。linq语法实际也是转换成了这些方法执行,有些操作只能用扩展方法而没有对应的linq语法。

绝大部分linq语句在定义的时候是不会执行的,只有当foreach语句执行的时候才会真正执行;只有聚合操作会立即执行。

常见操作符及说明   

操作符说明
Where
OfType<TResult>
筛选操作符定义了返回元素的条件。
在Where查询操作符中,可以使用调词。例如lambda表达式定义的谓词。来返回布尔值。
OfType<TResult>根据类型筛选元素,只返回TResult类型的元紊
Select
SelectMany
投射操作符用于把对象转换为另一个类型的新对象。Select和SelectMany定义了根据选择器函数选择结果值的投射
OrderBy
ThenBy
OrderByDescending
ThenByDescending
Reverse
排序操作符改变所返回的元素的顺序。
OrderBy按升序排序,
OrderByDescending 按降序排序。如果第一次排序的结果很类似,就可以使用ThenBy和ThenBy Descending操作符进行第二次排序。
Reverse反转集合中元素的顺序
Join
GroupJoin
连接操作符用于合并不直接相关的集合。使用Join操作符,可以根据键选择器函数连接两个集合,这类似于SOL中的JOIN。GroupJoin操作符连接两个集合,组合其结果
GroupBy
ToLookup
组合操作符把数据放在组中。GroupBy 操作符组合有公共键的元素。ToLookup通过创建一个一对多字典,来组合元素
Any
All
Contains
如果元素序列满足指定的条件,限定符操作符就返回布尔值。Any、All和Contains 都是限定符操作符。Any确定集合中是否有满足谓词函数的元素;All确定集合中的所有元素是否都满足谓词函数; Contains检查某个元素是否在集合中

Take
Skip
TakeWhile

SkipWhile

分区操作符返回集合的一个子集。Take、Skip、TakeWhile和 SkipWhile都是分区操作符。使用它们可以得到部分结果。使用Take必须指定要从集合中提取的元素个数:Skip跳过指定的元素个数,提取其他元素:TakeWhile提取条件为真的元素
Distinct
Union
Intersect
Except
Zip
Set操作符返回一个集合。
Distinct 从集合中删除重复的元素。除了Distinct之外,其他Set操作符都需要两个集合。
Union返回出现在其中一个集合中的唯一元素。
Intersect返回两个集合中都有的元素。
Except返回只出现在一个集合中的元素。
Zip把两个集合合并为一个
First
FirstOrDefault
Last
LastOrDefault
ElementAt
ElementAtOrDefault
Single
SingleOrDefault
这些元素操作符仅返回一个元素。
First返回第一个满足条件的元素。
FirstOrDefault类似于First,但如果没有找到满足条件的元素,就返回类型的默认值。Last:返回最后一个满足条件的元素。
ElementAt指定了要返回的元素的位置。
Single只返回一个满足条件的元素,如果有多个元素都满足条件,就抛出一个异常

Count
Sum
Min
Max

Average
Aggregate

聚合操作符计算集合的一个值!利用这些聚合操作符,可以计算所有值的总和、所有元素的个数、值最大和最小的元素i以及平均值等

ToArray
AsEnumerable
ToList
ToDictionary
Cast<TResult>

这些转换操作符将集合转换为数组:IEnunerable、IList、IDictionary 等

Empty
Range
Repeat

这些生成操作符返回一个新集合。
使用 Empty时集合是空的;
Range返回一系列数字;
Repeat返回一个始终重复一个值的集合

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DemoTests.test
{
	class Student
	{
		public int Id { get; set; }
		public string Code { get; set; }
		public string Name { get; set; }

		public int ClassId { get; set; }

		public decimal Score { get; set; }

		public override string ToString()
		{
			return $"[{Id},{Code},{Name},{ClassId},{Score}]";
		}
	}
	class Class
	{
		public int Id { get; set; }
		public string Code { get; set; }
		public string Name { get; set; }

		public override string ToString()
		{
			return $"[{Id},{Code},{Name}]";
		}
	}

	[TestClass]
	public class UnitTest1
	{
		[TestMethod]
		public void TestMethod1()
		{
			List<Student> stus = new List<Student>
			{
				new Student { Id = 1, ClassId = 1, Code = "01", Name = "张三", Score = 90 },
				new Student { Id = 2, ClassId = 2, Code = "02", Name = "李四", Score = 67 },
				new Student { Id = 3, ClassId = 2, Code = "03", Name = "王五", Score = 89 },
				new Student { Id = 4, ClassId = 3, Code = "04", Name = "马六", Score = 73 },
				new Student { Id = 5, ClassId = 3, Code = "05", Name = "小七", Score = 100 },
				new Student { Id = 5, ClassId = 4, Code = "06", Name = "牙九", Score = 66 }
			};
			List<Class> classes = new List<Class>
			{
				new Class { Id = 1, Code = "001", Name = "一班" },
				new Class { Id = 2, Code = "002", Name = "二班" },
				new Class { Id = 3, Code = "003", Name = "三班" }
			};
			//简单查询
			var state1 = from stu in stus 
								where stu.Score>80 
								orderby stu.Score 
								descending 
								select stu.Name;
			foreach(var t in state1)
			{
				Console.WriteLine(t);
			}

			//关联查询,左连接
			var state2 = from stu in stus 
								join c in classes on stu.ClassId equals c.Id into tt
								from c in tt.DefaultIfEmpty()
								select new { Stu = stu, Cls = c };
			foreach(var t in state2)
			{
				Console.WriteLine(t);
			}
			//分组查询
			var state3 = from stu in stus
						 group stu by stu.ClassId into t
						 select new { ClassId = t.Key, Count = t.Count() };
			foreach(var t in state3)
			{
				Console.WriteLine(t);
			}
		}
	}
}

并行LINQ

System.Linq.ParallelEnumerable,并行查询返回一个ParallelQuery<TSource>。

[TestMethod]
public void TestMethod2()
{
	Random r = new Random();
	var data = Enumerable.Range(0, 10000000).Select(x => r.Next(140)).ToList();
	double aver = data.AsParallel().Where(x => Math.Log(x) < 4).Select(x => x).Average();
	Console.WriteLine(aver);
}

 表达式树

在LNQ to Objects 中,扩展方法需要将一个委托类型作为参数,这样就可以将lambda表达式赋予参数。lambda表达式也可以赋予Expression<T>类型的参数。C#编译器根据类型给lambda表达式定义不同的行为。如果类型是Expression<T>,编译器就从lambda表达式中创建一个表达式树,并存储在程序集中。这样,就可以在运行期间分析表达式树,并进行优化,以便于查询数据源。

除了使用委托之外,编译器还会把表达式树放在程序集中。表达式树可以在运行期间读取。表达式树从派生自抽象基类Expression的类中构建。Expression类与 Expression<T>不同。继承自Expression类的表达式类有 BinaryExpression、ConstantExpression、InvocationExpression,lambdaExpression、NewExpression、NewArrayExpression、TermaryExpression和 Unary Expression等。编译器会从lambda表达式中创建表达式树。

DisplayTree()方法在控制台上图形化地显示表达式树。其中传递了一个Expression对象,并根据表达式的类型,把表达式的一些信息写到控制台上。根据表达式的类型,递归地调用DisplayTree()方法。

[TestClass]
public class UnitTest1
{
	[TestMethod]
	public void TestMethod3()
	{
		Expression<Func<int, bool>> expr = x => x.CompareTo(10) == 0;
		DisplayExprTree(0, "lambda", expr);
	}

	public void DisplayExprTree(int indent,string msg,Expression expr)
	{
		string output = string.Format("{0} {1}.  NodeType:{2};  Expr:{3}", 
		"".PadLeft(indent, ' '), msg, expr.NodeType, expr);
		indent++;
		switch(expr.NodeType)
		{
			case ExpressionType.Lambda:
				Console.WriteLine(output);
				LambdaExpression lambda = expr as LambdaExpression;
				foreach(var p in lambda.Parameters)
				{
					DisplayExprTree(indent, "Parameter", p);
				}
				DisplayExprTree(indent, "Body", lambda.Body);
				break;
			case ExpressionType.Constant:
				ConstantExpression constant = expr as ConstantExpression;
				Console.WriteLine("{0} Const Value: {1}", output, constant.Value);
				break;
			case ExpressionType.Parameter:
				ParameterExpression parameter = expr as ParameterExpression;
				Console.WriteLine("{0} Param Type: {1}", output, parameter.Type.Name);
				break;
			case ExpressionType.Equal:
			case ExpressionType.AndAlso:
			case ExpressionType.GreaterThan:
				BinaryExpression binary = expr as BinaryExpression;
				if (binary.Method != null)
					Console.WriteLine("{0} Method: {1}", output, binary.Method.Name);
				else
					Console.WriteLine(output);
				DisplayExprTree(indent, "Left", binary.Left);
				DisplayExprTree(indent, "Right", binary.Right);
				break;
			case ExpressionType.MemberAccess:
				MemberExpression member = expr as MemberExpression;
				Console.WriteLine("{0} Member Name: {1}, Type: {2}", output, member.Member.Name, member.Type.Name); ;
				DisplayExprTree(indent, "Member Expr", member.Expression);
				break;
			default:
				Console.WriteLine();
				Console.WriteLine("{0} {1}", expr.NodeType, expr.Type.Name);
				break;
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值