【Linq】标准查询操作符
A.1 聚合
聚合操作符(见表A-1),所有的结果只有一个值而不是一个序列。 Average 和 Sum 针对数值 (任何内置数值类型)序列或使用委托从元素值转换为内置数值类型的元素序列。 Min 和 Max 具有 不同数值类型的重载,不过也只能在对元素类型使用默认比较符或使用转换委托的序列上进行操 作。 Count 和 LongCount 是等价的,不同之处仅仅在于返回类型。它们两者都具有两个重载—— 一个只统计序列长度,一个可以接受谓词,即只统计与谓词匹配的元素。
string[] words = { "zero", "one", "two", "three", "four" };
int[] numbers = { 0, 1, 2, 3, 4 }; var n1 = numbers.Sum();
var n2 = numbers.Count();
var n3 = numbers.Average();
var n4 = numbers.LongCount(x => x % 2 == 0);
var n5 = numbers.Aggregate("seed", (current, item) => current + item, result => result.ToUpper()); var w1 = words.Min(word => word.Length);
var w2 = words.Max(word => word.Length);
最常见的聚合操作符就是 Aggregate (表A-1最后一行)。所有的其他聚合操作符都能表示 为对 Aggregate 的调用,虽然这样做会相对繁琐。其基本思想就是,总是存在以初始元素开头的 “当前结果”。聚合委托被应用于输入序列的每个元素;委托取得当前结果和输入元素,并生成下 一个结果。作为最终可选步骤,转换被应用于聚合结果上,并将其转换为这个方法的返回值。如 果有必要,这种转换可以产生不同的数据类型。这虽然不像听起来那么复杂,不过你依旧不希望 频繁地使用它。
所有的聚合操作符都使用立即执行的模式。没有使用谓词的 Count 方法的重载为实现了 ICollection 和 ICollection<T> 的类型进行了优化。届时,将使用集合的 Count 属性,无须读 取任何数据 。LongCount 没有这种优化。我个人从来没有在LINQ to Objects中使用过这个方法。
A.2 连接
只存在一个连接操作符: Concat (见表A-2)。如你所料,它会对两个序列进行操作,并 返回一个单独的序列,该序列中包含了第1个序列和第2个序列中所有元素,且第2个序列连接 在第1个序列的后面。两个输入序列必须具有相同的类型,使用延迟执行模式,并且均为流式 数据。
int[] numbers = { 0, 1, 2, 3, 4 };
var n = numbers.Concat(new[] { 1, 2, 3 });
A.3 转换
转换操作符被广泛地使用,不过它们总是成对出现。
object[] allStrings = { "These", "are", "all", "strings" };
object[] notAllStrings = { "Number", "at", "the", "end", 5 };
string[] words = { "zero", "one", "two", "three", "four" };
int[] numbers = { 0, 1, 2, 3, 4 }; var a1 = allStrings.Cast<string>();
var a2 = allStrings.OfType<string>(); var n1 = notAllStrings.Cast<string>();
var n2 = notAllStrings.OfType<string>(); var b1 = numbers.ToArray();
var b2 = numbers.ToList(); var w1 = words.ToDictionary(w => w.Substring(0, 2));
var w2 = words.ToLookup(word => word[0]);
var w3 = words.ToDictionary(word => word[0]); //已添加了具有相同键的项
ToArray 和 ToList 的含义显而易见:它们读取整个序列到内存中,并把结果作为一个数组 或一个 List<T> 返回。两者都是立即执行。
Cast 和 OfType 把一个非类型化序列转换为类型化的,或抛出异常(对于 Cast ),或忽略那 些不能隐式转换为输出序列元素类型的输入序列元素(对于 OfType )。这个运算符也能用于把某 个类型化序列转换为更加具体的类型化序列,例如把 IEnumerable<object> 转换为 IEnumerable<string> 。转换以流的方式延迟执行。
ToDictionary 和 ToLookup 都使用委托来获得任何特定元素的键。 ToDictionary 返回一个 把键映射到元素类型的字典,而 ToLookup 返回相应的类型化的 ILookup<,> 。查找类似于查字 典,只不过和健相关的值不是一个元素而是元素的序列。查找通常用于普通操作中希望有重复的 键存在的时候,而重复的键会引起 ToDictionary 抛出异常。两者更复杂的重载方法可以将自定 义的 IEqualityComparer<T> 用于比较键的操作,并在每个元素被放到字典或者开始查找之前, 把转换委托应用于其上。另外,两个方法都会使用立即执行的模式。
我没有提供 AsEnumerable 和 AsQueryable 这两个操作符的例子,因为它们不会以一种显而 易见的方式立即影响结果。但它们影响查询执行的方式。 Queryable.AsQueryable 是返回一个 IQueryable 类型(既可以是泛型,也可以是非泛型,取决于你选取的重载)的 IEnumerable 上的扩展方法。如果调用的 IEnumerable 已经是一个 IQueryable ,则它会返回同一个引用,否 则就创建一个包装类来包含原始序列。通过这个包装类,你可以使用所有普通的 Queryable 扩展 方法,在表达式树中传递,不过在查询执行的时候,表达式树被编译为普通的IL代码直接执行。 LambdaExpression.Compile 的用法已经在9.3.2节中讲到过。
Enumerable.AsEnumerable 是 IEnumerable<T> 的扩展方法,包含一些简单的实现,仅返 回被调用者的引用。这次不会用到包装类——仅返回同一个引用。
它强制 Enumerable 扩展方法 用于随后的LINQ操作符。思考一下如下查询表达式:
var query1 = from user in context.Users
where user.Name.StartWith("Tim")
select user; var query2 = from user in context.Users.AsEnmuerable()
where user.Name.StartWith("Tim")
select user;
第2个查询表达式强制编译时的源类型为 IEnumerable<User> 而非 IQueryable <User> , 因而所有的处理过程都可以在内存中而不必在数据库中完成。编译器将使用 Enumerable 的扩展 方法(它获取委托参数)而不是 Queryable 的扩展方法(它获取表达式树参数)。通常而言,你 希望尽可能在SQL中完成大多数处理,但在遇到需要“本地”代码参与转换的时候,你有时不得 不强制LINQ去使用适当的 Enumerable 扩展方法。当然,这不仅仅针对数据库,其他提供器也可 以在查询末端强制使用 Enumerable ,只要它们基于 IQueryable 及其同类即可。
A.4 元素操作符
另外一种用于选择数据的查询操作符,分组后成对显示在表A-4中。这次,每一对操作符都以 同样的方式执行。选取单个元素的简化版本,就是在特定元素存在时返回它,不存在时就抛出一个 异常,还有一个以 OrDefault 结尾的版本。 OrDefault 版本的功能完全一样,只是在找不到想要 的元素时,返回结果类型的默认值,而非抛出一个异常。所有操作符都使用立即执行的模式。
string[] words = { "zero", "one", "two", "three", "four" }; var w1 = words.ElementAt();
var w2 = words.ElementAtOrDefault();
var w3 = words.First();
var w4 = words.First(w => w.Length == );
var w5 = words.First(w => w.Length == ); //异常
var w6 = words.FirstOrDefault(w => w.Length == );
var w7 = words.Last();
var w8 = words.Single();
var w9 = words.Single(w => w.Length == ); //异常
var w10 = words.SingleOrDefault();
var w11 = words.SingleOrDefault(w => w.Length == );
操作符的名称很容易理解: First 和 Last 分别返回序列的第1个和最后1个元素,如果序列为 空,抛出 InvalidOperationException 异常。 Single 返回序列中的一个元素,如果序列为空 或者返回一个以上的元素则抛出异常,而 ElementAt 通过索引返回特定的元素(例如,第5个元 素)。如果索引为负数或大于集合中元素的实际数量,将抛出 ArgumentOutOfRangeException 。 另外,除了 ElementAt 首先过滤序列以外,所有的操作符都存在相应的重载方法——例如, First 可以返回匹配给定条件的第1个元素。
以上这些方法的 OrDefault 版本都不会抛出异常,而是返回元素类型的默认值。但有一种例 外情况:如果序列为空(empty), SingleOrDefault 将返回默认值,但如果序列中的元素不止 一个,将抛出异常,就像 Single 方法一样。该方法适用于所有条件正确,序列只包含0或1个元 素的情况。如果你要处理的序列可能包含多个元素,应该使用 FirstOrDefault 方法。
所有没有使用谓词参数的重载都为 IList<T> 的实例进行了优化,因为它们不通过迭代就可 以访问正确的元素。包含谓词的版本没有优化,因为这对大多数调用都没有意义,尽管从末尾向 后移动,会使查找列表中最后一个匹配元素的过程产生很大不同。在本书写作之时,这种情况还 没有优化,未来版本也许会发生改变。
A.5 相等操作
只有一个标准的相等操作符: SequenceEqual (见表A-5)。它是按照顺序逐一比较两个序 列中的元素是否相等。例如,序列0,1,2,3,4不等于4,3,2,1,0。重载方法允许使用具体 的 IEqualityComparer<T> ,对元素进行比较。返回值就是一个Boolean值,并使用立即执行的 模式来计算。
string[] words = { "zero", "one", "two", "three", "four" }; var b1 = words.SequenceEqual(new[] { "zero", "one", "two", "three", "four" });
var b2 = words.SequenceEqual(new[] { "ZERO", "ONE", "TWO", "THREE", "FOUR" });
var b3 = words.SequenceEqual(new[] { "ZERO", "ONE", "TWO", "THREE", "FOUR" }, StringComparer.OrdinalIgnoreCase);
同样,LINQ to Objects在这里也没有进行优化:如果存在有效的方式可以得到两个序列的数 量,那么在比较它们的元素之前,就能知道它们是否相等了。而实际上,该方法的实现直接遍历 两个序列,直到末尾或找到不等的元素。
A.6 生成
在所有的生成操作符(见表A-6)中,只有一个会对现有的序列进行处理: DefaultIfEmpty 。如果序列不为空,就返回原始序列,否则返回含有单个元素的序列。其中的元素通常是序列类型 的默认值,不过重载方法允许你设定要使用的值。
int[] numbers = { , , , , }; var n1 = numbers.DefaultIfEmpty();
var n2 = new int[].DefaultIfEmpty(); var n3 = new int[].DefaultIfEmpty(); var n4 = Enumerable.Range(, );
var n5 = Enumerable.Range(, );
var n6 = Enumerable.Empty<int>();
其他3个生成操作符仅仅是 Enumerable 的静态方法。
Range 生成一个整数序列,通过参数可以设定第一个值和需要生成值的个数。
Repeat 根据指定的次数来重复特定的单个值,以生成任意类型的序列。
Empty 生成任意类型的空序列。
所有生成操作符都使用延迟执行,并对结果进行流式处理。也就是说,它们不会预先生成集 合并返回。不过,返回正确类型的空数组的 Empty 方法是个例外。一个空的数组是完全不可变的, 因此相同元素类型的所有这种调用,都将返回相同的空数组。
A.7 分组
有两个分组操作符,不过其中一个就是 ToLookup (我们已经在A-3中讲述转换操作符的 时候看到过了)。剩下的 GroupBy ,已经在11.6.1节中讨论查询表达式中的 group... by 子句 时见过。它使用延迟执行,不过会缓存结果。当你开始迭代分组的结果序列时,消费的是整 个输入序列。
GroupBy 的结果是相应类型化 IGrouping<,> 元素的序列。每个元素具有一个键和与之匹配 的元素序列。从许多方面讲,它只是查找的一种不同的方式——不是通过键随机访问分组数据, 而是顺序枚举它。分组数据的返回顺序是它们各自键被发现的顺序。在一个分组数据内,元素的 顺序和最初序列中的一致。
GroupBy 具有大量的重载方法,你既可以设定从元素派生出键的方式(这一项是必须指定 的),也可以有选择地设定如下内容。
1.如何比较键。
2.从原始元素到分组内元素的投影。
3.包含键和匹配元素序列的投影。这时,整个结果为投影结果类型的元素序列。
表A-7包含了第二个和第三个选项的示例,当然还有最简单的形式。自定义键比较器不是三 言两语就能概括的,不过它们的工作方式一目了然。
string[] words = { "zero", "one", "two", "three", "four" }; var w1 = words.GroupBy(word => word.Length); var w2 = words.GroupBy(word => word.Length, //键
word => word.ToUpper()); //分组元素 var w3 = words.GroupBy(word => word.Length,
(Key, g) => Key + ":" + g.Count());
//归集每个部门信息
var deptList = from emp in empList
where emp.Status == "在职" //筛选“在职”员工
orderby emp.DeptID ascending //按“部门ID”排序
group emp by new //按“部门ID”和“部门名称”分组
{
emp.DeptID,
emp.DeptName
}
into g
select new DeptInfo()
{
DeptID = g.Key.DeptID,
DeptName = g.Key.DeptName,
EmplayeeCount = g.Count(), //统计部门员工数量
WageSum = g.Sum(a => a.Wage), //统计部门工资总额
WageAvg = g.Average(a => a.Wage), //统计部门平均工资
EmplayeeList = (from e in g //归集部门员工列表
select new Emplayee()
{
EmpID = e.EmpID,
EmpName = e.EmpName
}
).ToList() });
A.8 连接
有两个操作符用于连接,即 Join 和 GroupJoin ,我们在11.5节分别使用 join 和 join...into 查 询表达式子句的时候看到过这两个操作符。每个方法都可以获取几个参数:两个序列、用于每个序 列的键选择器,应用于每个匹配元素对的投影,以及可选的键比较器。
对于 Join ,投影从每个序列中获取一个元素,并生成一个结果;对于 GroupJoin ,投影从 左边序列获取一个元素,然后从右边序列获取一个由匹配元素构成的序列。两者都是延迟执行, 并流处理左边序列,而对于右边序列,在请求第一个结果时便读取其全部内容。
对于在表A-8的连接例子中,我们将按照姓名和颜色的第一个字母把一个姓名序列(Robin、 Ruth、Bob、Emma)匹配到一个颜色序列(Red、Blue、Beige、Green),例如,Robin将会和Red 连接上,Blue和Beige连接。
string[] names = { "Robin", "Ruth", "Bob", "Emma" };
string[] colors = { "Red", "Blue", "Beige", "Green" }; var j1 = names.Join //左边序列
(colors, //右边序列
name => name[], //左边选择器
color => color[], //右边选择器
//为结果投影
(name, color) => name + " - " + color); /* Robin - Red
* Ruth - Red
* Bob - Blue
* Bob - Beige */ var j2 = names.GroupJoin
(colors,
name => name[],
color => color[],
//为键/序列对投影
(name, matches) => name + ":" +
string.Join("/", matches.ToArray())); /* Robin:Red
Ruth:Red
Bob:Blue/Beige
Emma: */
注意,Emma未匹配任何颜色——所以,该姓名不会显示在第一个例子的结果中,但却会显 示在第二个例子中,只是颜色序列是空的。
A.9 分部
分部操作符中,既可以跳过(skip)序列的开始部分,只返回剩余元素,也可以只获取(take) 序列的开始部分,而忽略剩余元素。在每种情况下,你都可以设置序列的第一部分包含多少个元 素,或设定相应的条件——只要条件满足,序列的第一部分就继续往前进行。在条件第一次不满 足时,就不再往下判断——而不管序列的后面元素是否匹配。所有的部分操作符(见表A-9)都 是延迟执行和流式数据。
通过位置或谓词,分组可以将一个序列有效地划分成两个单独的部分。在这两种情况下, 如果你将 Take 或 TakeWhile 的结果与相对应的 Skip 或 SkipWhile 的结果进行连接,并为两种 调用提供相同的参数,将得到原始序列:每个元素都按原始顺序出现一次。表A-9演示了这种 调用。
string[] words = { "zero", "one", "two", "three", "four" }; var w1 = words.Take();
var w2 = words.Skip();
var w3 = words.TakeWhile(word => word.Length <= );
var w4 = words.SkipWhile(word => word.Length <= );
A.10 投影
我们在第11章看到过这两个投影操作符( Select 和 SelectMany )。 Select 是一种简单 的从源元素到结果元素的一对一投影。 SelectMany 在查询表达式中有多个 from 子句的时候 使用;原始序列中的每个元素都用来生成新的序列。两个投影操作符(见表A-10)都是延迟 执行。
string[] words = { "zero", "one", "two", "three", "four" }; var w1 = words.Select(word => word.Length);
var w2 = words.Select(
(word, index) =>
index + ":" + word); var w3 = words.SelectMany(word => word.ToCharArray()); var w4 = words.SelectMany(
(word, index) =>
Enumerable.Repeat(word, index));
这里包含了第11章没有介绍的重载。这两种方法都含有允许在投影中使用原始序列索引的重载,并且 SelectMany 还可以将所有生成的序列合并成一个单独的序列,而不包含原始序列 ,或使用投影来为每个元素对生成结果元素。多个 from 子句通常使用的是包含投影的重载。(篇幅所限,恕不举例,详细内容参见第11章。)
.NET 4引入了一个新的操作符 Zip 。根据MSDN所述,它并不是一个标准的查询操作符,但 还是有必要了解一下。它包含两个序列,并对每个元素对应用指定的投影:先是每个序列的第一 个元素,然后是每个序列的第二个元素,以此类推。任何一个源序列达到末尾时,结果序列都将 停止产生。表A-11展示了 Zip 的两个示例,使用了A.8节中的名称和颜色。 Zip 使用了延迟执行和 流式数据。
string[] names = { "Robin", "Ruth", "Bob", "Emma" };
string[] colors = { "Red", "Blue", "Beige", "Green" }; var n1 = names.Zip(colors, (x, y) => x + "-" + y); //第二个序列提前停止生成
var n2 = names.Zip(colors.Take(), (x, y) => x + "-" + y);
A.11 数量
数量操作符(见表A-12)都返回一个Boolean值,使用立即执行。
All 操作符检查在序列中的所有元素是否满足指定的条件。
Any 操作符检查在序列中的任意元素是否满足指定的谓词,如果使用没有参数的重载,则检查序列中是否存在元素。
Contains 操作符检查序列是否包含特殊的元素,可选设置要使用的比较方式。
string[] words = { "zero", "one", "two", "three", "four" }; var w1 = words.All(word => word.Length > );
var w2 = words.All(word => word.Length > );
var w3 = words.Any();
var w4 = words.Any(word => word.Length == );
var w5 = words.Any(word => word.Length == );
var w6 = words.Contains("FOUR");
var w7 = words.Contains("FOUR", StringComparer.OrdinalIgnoreCase);
A.12 过滤
两个过滤操作符是 OfType 和 Where 。有关 OfType 操作符的细节和例子,请参见转换操作符 一节(A.3节)。 Where 运算符返回一个序列,这个序列包括与给定谓词匹配的所有元素。它还有 一个重载方法,以便谓词能使用元素索引。通常是不需要索引的,而在查询表达式中的 where 子 句也不使用这个重载方法。 Where 总是使用延迟执行和流式数据,表A-13列出了两个重载方法。
string[] words = { "zero", "one", "two", "three", "four" }; var w1 = words.Where(word => word.Length > ); //"zero", "three", "four" var w2 = words.Where((word, index) => index < word.Length); //
/* "zero", // index=0, length=4
"one", // index=1, length=3
"two", // index=2, length=3
"three", // index=3, length=5
// Not "four", index=4, length=4 */
A.13 基于集的操作符
把两个序列看作元素的集合是很自然的。4个基于集合的运算符都具有两个重载方法,一个 使用元素类型的默认相等比较,一个用于在额外的参数中指定比较。所有的集合运算符都是延迟 执行。
Distinct 操作符最简单——它只对单个序列起作用,并且返回所有不重复元素(已经排除了重复项)的新序列。其他的运算符也确保只返回不重复的元素,不过它们对两个序列起作用。
1. Intersect 返回在两个序列中都出现的元素。
2. Union 返回出现在任一序列中的元素。
3. Except 返回出现在第一个序列,但不出现在第二个序列中的元素(出现第二个序列但不在第一个中的元素也不返回)。
表A-14中这些操作符的示例使用了两个新序列,即 abbc ( "a" , "b" , "b" , "c" )和 cd ( "c" , "d" )。
string[] abbc = { "a", "b", "b", "c" };
string[] cd = { "c", "d" }; var a1 = abbc.Distinct(); //"a", "b", "c"
var a2 = abbc.Intersect(cd); // "c"
var a3 = abbc.Union(cd); // "a", "b", "c", "d"
var a4 = abbc.Except(cd); // "a", "b"
var a5 = cd.Except(abbc); // "d"
所有这些操作符都使用延迟执行,但有的使用了缓冲,有的使用了流式处理,缓冲和流式处理显然更复杂一些。 Distinct 和 Union 都对输入序列进行了流式处理,而 Intersect 和 Except先是读取整个右边输入序列,然后像连接操作符那样对左边输入序列进行流式处理。所有这些操作符都保存已返回元素的集,以确保不返回重复的元素。这意味着即使是 Distinct 和 Union ,也不适合那些过大而不适于放入内存的序列,除非你知道经过处理后的集并不会包含很多元素。
A.14 排序
我们之前见过所有的排序运算符: OrderBy 和 OrderByDescending 提供了“主要的”排序 方式,而 ThenBy 和 ThenByDescending 提供了次要的排序方式,用以区别使用主要的排序方式 无法区别的元素。在每种情况中,都要指定从元素到排序键的投影,也指定键之间的比较。不像 框架中的其他排序算法(比如 List<T>.Sort ),LINQ排序比较稳定——换句话说,如果两个元 素根据它们的排序关键字被认为是相等的,那么将按照它们在原始序列中的顺序返回。
最后一个排序操作符是 Reverse ,它仅反转序列的顺序。所有的排序操作符(见表A-15)都 是延迟执行,不过会缓存其中的数据。
string[] words = { "zero", "one", "two", "three", "four" }; //以首字母顺序排序
var w1 = words.OrderBy(word => word); //"four", "one","three","two", "zero" // 依据第二个字母对单词排序
var w2 = words.OrderBy(word => word[]); //"zero", "three","one","four", "two" // 依据长度对单词排序,如长度相同则以原顺序返回
var w3 = words.OrderBy(word => word.Length); //"one", "two","zero","four", "three" var w33 = words.OrderByDescending(word => word.Length); //"three", "zero", "four", "one", "two" // 依据长度排序,如长度相同则以首字母顺序排序
var w4 = words.OrderBy(word => word.Length).ThenBy(word => word); //"one", "two","four","zero", "three" // 依据长度排序,如长度相同则按反向字母顺序排序
var w5 = words.OrderBy(word => word.Length).ThenByDescending(word => word); //"two", "one","zero","four", "three" //反转序列
var w6 = words.Reverse(); //"four", "three", "two","one", "zero"
【Linq】标准查询操作符的更多相关文章
- Linq 标准查询操作符三
本文介绍了LINQ标准查询操作符.没有这些操作符,LINQ就不会存在.本文为理解这些操作符的功能提供了很好的基础.了解它们将会很有帮助,因为LINQ的各种Provider都是基于这些操作符来完成各自丰 ...
- LINQ 标准查询操作符
本文介绍了LINQ标准查询操作符.没有这些操作符,LINQ就不会存在.本文为理解这些操作符的功能提供了很好的基础.了解它们将会很有帮助,因为LINQ的各种Provider都是基于这些操作符来完成各自丰 ...
- LINQ标准查询操作符详解(转)
一. 关于LINQ LINQ 英文全称是“Language-Integrated Query”,中文为“语言集成查询”,它是微软首席架构师.Delphi 之父和C# 之父——Anders ...
- LINQ标准查询操作符(三)——Aggregate、Average、Distinct、Except、Intersect、Union、Empty、DefaultIfEmpty、Range、Repeat
七.聚合操作符 聚合函数将在序列上执行特定的计算,并返回单个值,如计算给定序列平均值.最大值等.共有7种LINQ聚合查询操作符:Aggregate.Average.Count.LongCount.Ma ...
- 【LINQ标准查询操作符总结】之聚合操符
C# 中的LINQ 提供了两种操作方式,查询表达式和查询操作符,所有的查询表达式都有对应的查操作符类替代,查询表达式有点“类” SQL,在代码中写SQL,总觉得不够“优雅”,使用查询操作符就显得“优 ...
- LINQ标准查询操作符(四) —AsEnumerable,Cast,OfType,ToArray,ToDictionary,ToList,ToLookup,First,Last,ElementAt
十.转换操作符 转换操作符是用来实现将输入对象的类型转变为序列的功能.名称以“As”开头的转换方法可更改源集合的静态类型但不枚举(延迟加载)此源集合.名称以“To”开头的方法可枚举(即时加载)源集合并 ...
- LINQ标准查询操作符(五)
十二.相等操作符 如果两个序列的对应元素相等且这两个序列具有相同数量的元素,则视这两个序列相等. SequenceEqual方法通过并行地枚举两个数据源并比较相应元素来判断两个序列是否相等.如果两个序 ...
- LINQ标准查询操作符(二)——Join、GroupJoin、GroupBy、Concat、
四.联接操作符 联接是指将一个数据源对象与另一个数据源对象进行关联或者联合的操作.这两个数据源对象通过一个共同的值或者属性进行关联. LINQ有两个联接操作符:Join和GroupJoin. 1. J ...
- LINQ标准查询操作符(一)——select、SelectMany、Where、OrderBy、OrderByDescending、ThenBy、ThenByDescending和Reverse
一.投影操作符 1. Select Select操作符对单个序列或集合中的值进行投影.下面的示例中使用select从序列中返回Employee表的所有列: //查询语法 var query = fro ...
- Linq标准查询操作符
Linq的出现让代码简洁了不少.之前在项目中基本都在使用它,但是没有完整的整理过,今天借这个周末,将其进行整理,方便后期对其的使用.Linq的操作可以分为聚合,连接,转换,元素操作符,相等操作,生成 ...
随机推荐
- linux中man手冊的高级使用方法
Linux提供了丰富的帮助手冊.当你须要查看某个命令的參数时不必到处上网查找.仅仅要man一下就可以. Linux 的man手冊共同拥有下面几个章节: 1.Standard commands (标准命 ...
- OpenCV2马拉松第17圈——边缘检測(Canny边缘检測)
计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g 收入囊中 利用OpenCV Canny函数进行边缘检測 掌握Canny算法基本理论 ...
- apache ua Custom Log Formats
RewriteEngine OnRewriteBase / RewriteCond %{HTTP_USER_AGENT} (android|bb\d+|meego).+mobile|avantgo|b ...
- centos上装eclipse步骤
1.去官网下个eclipse for linux的 地址:http://www.eclipse.org/downloads/ Eclipse IDE for Java EE Developer ...
- Bing Maps进阶系列四:路由功能服务(RouteService)
Bing Maps进阶系列四:路由功能服务(RouteService) Bing Maps提供的路由功能服务(RouteService)可以实现多方位的计算地图上的路线指示,路径行程等功能,比如说实现 ...
- [bzoj5404]party
https://zybuluo.com/ysner/note/1240918 题面 这题面不好概括啊 解析 \(5pts\)算法 既然\(q=0\),打上文件输入输出即可. 当然不开够空间且不特判的小 ...
- bzoj2125 最短路——仙人掌两点间距离
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2125 仙人掌!模仿 lyd 的代码写的,也算是努力理解了: 主要分成 lca 在环上和不在环 ...
- css的一些命名规范
网页制作中规范使用DIV+CSS命名规则,可以改善优化功效特别是团队合作时候可以提供合作制作效率,具体DIV CSS命名规则CSS命名大全内容篇. 常用DIV+CSS命名大全集合,即CSS命名规则 D ...
- Unity基本操作
主要内容: C#学习 Unity项目 打砖块:BreakBricks Unity操作 Unity操作: 调试 碰撞体 触发器 视角 键盘视角平移 光照贴图 游戏对象Gameobject 访问对象 实体 ...
- Windows和Centos下Docker的安装配置
Windows和Centos下Docker的安装配置 windows环境下的安装(win10) 在Windows系统上需要利用toolbox来安装Docker,现在 Docker 有专门的 Win10 ...