LINQ学习之旅——第一站"LTO"之延时标准查询操作符(下)
今天我们继续上一节的内容,讲解剩余的几个延时标准查询操作符。
14.Join操作符
(1)作用:用于连接两个序列,就像是SQL里的Join语句连接多表一样;
(2)方法原型:
public static IEnumerable<V> Join<T,U,K,V>(
this IEnumerable<T> source,
IEnumerable<U> inner,
Func<T,K> outerKeySelector,
Func<U,K> innerKeySelector,
Func<T,U,V>resultSelector);
(3)原型说明:Join操作符的方法原型定义比较复杂,从原型定义中可以看到,参数outer和inner是要连接的两个输入序列,在调用Join操作符时,首先从把序列inner中的每一个类型为U的元素作为委托innerKeySelector输入参数传递给具体的委托方法,返回一个类型为K的对象innerKey作为连接关键字,将inner序列中的每一个元素和其对应的连接关键字innerKey存储在一个临时哈希表中。接下来列举outer序列中所有元素,把每一个类型为T的元素作为委托outerKeySelector输入参数传递给具体的委托方法,返回一个类型为K的对象outerKey作为连接关键字,并从第一步中生成的临时哈希表中查找和关键字outerKey相等的innerKey对象,如果找到,会将当前outer序列中类型为T的元素和对应的inner序列中类型为U的元素作为委托resultSelector的两个输入参数传递给委托的具体方法,委托resultSelector根据这两个参数一个类型为V的对象,把该对象添加进结果序列中去,所以操作符Join最后返回的序列类型为IEnumerable<V>;
(4)示例验证:
①雇员类:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 //雇员类 2 publicclass Employee 3 { 4 publicstring Id { get; set; }//雇员号 5 6 publicstring Name { get; set; }//姓名 7 8 publicint Age { get; set; }//年龄 9 10 //重新实现ToString()方法 11 publicoverridestring ToString() 12 { 13 return"{Id="+ Id +", Name="+ Name +", Age="+ Age +"}"; 14 } 15 }
②薪水类:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 //薪水类 2 publicclass Salary 3 { 4 publicstring EmployeeId { get; set; }//雇员号 5 6 publicdouble Wage { get; set; }//工资 7 8 publicdouble Bonus { get; set; }//奖金 9 10 public DateTime SalaryTime { get; set; }//发薪时间 11 12 //重新实现ToString()方法 13 publicoverridestring ToString() 14 { 15 return"{EmployeeId="+ EmployeeId +", Wage="+ Wage +", Bonus="+ Bonus +", SalaryTime="+ SalaryTime +"}"; 16 } 17 }
③调用操作符Join:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 //定义雇员数组 4 Employee[] employees =new Employee[] 5 { 6 new Employee{Id="0001",Name="张三",Age=32}, 7 new Employee{Id="0002",Name="李四",Age=31}, 8 new Employee{Id="0003",Name="王五",Age=32}, 9 new Employee{Id="0004",Name="小六",Age=25}, 10 new Employee{Id="0005",Name="张麻子",Age=40}, 11 new Employee{Id="0006",Name="王小二",Age=25}, 12 new Employee{Id="0007",Name="灭绝师太",Age=55}, 13 }; 14 15 //定义雇员薪水数组 16 Salary[] salarys=new Salary[] 17 { 18 new Salary{EmployeeId="0001",Wage=1700,Bonus=2500,SalaryTime=new DateTime(2011,7,15)}, 19 new Salary{EmployeeId="0002",Wage=1500,Bonus=2500,SalaryTime=new DateTime(2011,7,15)}, 20 new Salary{EmployeeId="0003",Wage=1700,Bonus=3000,SalaryTime=new DateTime(2011,7,15)}, 21 new Salary{EmployeeId="0004",Wage=1000,Bonus=2000,SalaryTime=new DateTime(2011,7,15)}, 22 new Salary{EmployeeId="0005",Wage=2000,Bonus=4000,SalaryTime=new DateTime(2011,7,15)}, 23 new Salary{EmployeeId="0006",Wage=1000,Bonus=2000,SalaryTime=new DateTime(2011,7,15)}, 24 new Salary{EmployeeId="0007",Wage=3000,Bonus=5000,SalaryTime=new DateTime(2011,7,15)}, 25 new Salary{EmployeeId="0001",Wage=1700,Bonus=3000,SalaryTime=new DateTime(2011,8,15)}, 26 new Salary{EmployeeId="0002",Wage=1500,Bonus=3000,SalaryTime=new DateTime(2011,8,15)}, 27 new Salary{EmployeeId="0003",Wage=1700,Bonus=4000,SalaryTime=new DateTime(2011,8,15)}, 28 }; 29 30 Console.WriteLine("调用Join操作符:"); 31 Console.WriteLine("------------------------------------"); 32 33 var list = employees.Join(salarys, 34 e => e.Id, 35 s => s.EmployeeId, 36 (e, s) =>new 37 { 38 Name = e.Name, 39 Wage = s.Wage, 40 Bonus = s.Bonus, 41 SalaryTime = s.SalaryTime 42 }); 43 44 Console.WriteLine("雇员薪水发放情况:"); 45 foreach (var e in list) 46 { 47 Console.WriteLine(e); 48 } 49 50 Console.Read(); 51 }
④结果:
15.GroupJoin操作符
(1)作用:与Join操作符相同,也是用于连接两个输入序列;
(2)方法原型:
public static IEnumerable<V> GroupJoin<T,U,K,V>(
this IEnumerable<T> source,
IEnumerable<U> inner,
Func<T,K> outerKeySelector,
Func<U,K> innerKeySelector,
Func<T,U,V>resultSelector);
(3)原型说明:尽管操作符GroupJoin的原型定义和Join相同,但是它们的方法实现是有区别的。Join操作符在列举outer序列元素时,将一个outer序列元素和其对应的inner序列元素作为委托resultSelector的输入参数,意味着如果一个outer序列元素有多个对应的inner序列元素,那么Join操作符是分多次将outer序列元素和和其对应的inner序列元素传递给委托resultSelector,而对于GroupJoin操作符,如果一个outer序列元素有多个对应的inner序列元素的话,那么这多个对应的inner序列元素是作为一个序列一次性传递给委托resultSelector;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 //定义雇员数组 4 Employee[] employees =new Employee[] 5 { 6 new Employee{Id="0001",Name="张三",Age=32}, 7 new Employee{Id="0002",Name="李四",Age=31}, 8 new Employee{Id="0003",Name="王五",Age=32}, 9 new Employee{Id="0004",Name="小六",Age=25}, 10 new Employee{Id="0005",Name="张麻子",Age=40}, 11 new Employee{Id="0006",Name="王小二",Age=25}, 12 new Employee{Id="0007",Name="灭绝师太",Age=55}, 13 }; 14 15 //定义雇员薪水数组 16 Salary[] salarys=new Salary[] 17 { 18 new Salary{EmployeeId="0001",Wage=1700,Bonus=2500,SalaryTime=new DateTime(2011,7,15)}, 19 new Salary{EmployeeId="0002",Wage=1500,Bonus=2500,SalaryTime=new DateTime(2011,7,15)}, 20 new Salary{EmployeeId="0003",Wage=1700,Bonus=3000,SalaryTime=new DateTime(2011,7,15)}, 21 new Salary{EmployeeId="0004",Wage=1000,Bonus=2000,SalaryTime=new DateTime(2011,7,15)}, 22 new Salary{EmployeeId="0005",Wage=2000,Bonus=4000,SalaryTime=new DateTime(2011,7,15)}, 23 new Salary{EmployeeId="0006",Wage=1000,Bonus=2000,SalaryTime=new DateTime(2011,7,15)}, 24 new Salary{EmployeeId="0007",Wage=3000,Bonus=5000,SalaryTime=new DateTime(2011,7,15)}, 25 new Salary{EmployeeId="0001",Wage=1700,Bonus=3000,SalaryTime=new DateTime(2011,8,15)}, 26 new Salary{EmployeeId="0002",Wage=1500,Bonus=3000,SalaryTime=new DateTime(2011,8,15)}, 27 new Salary{EmployeeId="0003",Wage=1700,Bonus=4000,SalaryTime=new DateTime(2011,8,15)}, 28 }; 29 30 Console.WriteLine("调用GroupJoin操作符:"); 31 Console.WriteLine("------------------------------------"); 32 33 var list1 = employees.GroupJoin(salarys, 34 e => e.Id, 35 s => s.EmployeeId, 36 (e, s) =>new 37 { 38 Name = e.Name, 39 TotalWage = s.Sum(i=>i.Wage), 40 TotalBonus = s.Sum(i=>i.Bonus), 41 }); 42 43 Console.WriteLine("各个雇员的薪水总和发放情况:"); 44 foreach (var e in list1) 45 { 46 Console.WriteLine(e); 47 } 48 49 Console.Read(); 50 }
结果:
16.GroupBy操作符
(1)作用:用于将输入序列中的元素分组;
(2)方法原型:
①原型定义:
public static IEnumerable<IGrouping<K,T>> GroupBy<T,K>(
this IEnumerable<T> source,
Func<T,K> keySelector);
②原型定义:
public static IEnumerable<IGrouping<K,T>> GroupBy<T,K>(
this IEnumerable<T> source,
Func<T,K> keySelector,
IEqualityComparer<K> comparer);
③原型定义:
public static IEnumerable<IGrouping<K,E>> GroupBy<T,K,E>(
this IEnumerable<T> source,
Func<T,K> keySelector,
Func<T,E> elementSelector);
④原型定义:
public static IEnumerable<IGrouping<K,E>> GroupBy<T,K,E>(
this IEnumerable<T> source,
Func<T,K> keySelector,
Func<T,E> elementSelector,
IEqualityComparer<K> comparer);
(3)原型说明:GroupBy操作符有四个原型定义,发现前两种方法的返回类型都是为IEnumerable<IGrouping<K,T>>,它包含的元素类型为IGrouping<K,T>的序列类型。接口IGrouping<K,T>的定义代码如下:
public interface IGrouping<K,T>:IEnumerable<T>
{
K Key { get; }
}
很明显接口 IGrouping<K,T>是实现了IEnumerable<T>接口,且带有一个类型为K的只读属性Key的序列,序列内部元素的类型为T,所以说GroupBy返回的是一个包含元素类型为序列的序列。当调用GroupBy操作符时,把输入序列source中的每一个元素作为输入参数传递给委托keySelector,委托keySelector根据传入类型为T的参数返回一个类型为K的对象key,接着把具有相同key的输入元素作为一组,和对应的key对象一起生成一个IGrouping<K,T>序列,最后把这样一组组的IGrouping<K,T>序列组成类型为IEnumerable<IGrouping<K,T>> 的序列返回。第二种原型和第一种的区别在于方法多了一个类型为IEqualityComparer<K>的参数,它是用来辅助比较两个对象是否相等,在这里是对委托keySelector返回的值进行比较,它允许开发人员自定义比较逻辑。相比于第一种采用的是默认相等比较器EqualityComparer<T>.Default对输入元素进行比较。第二种显得更加灵活。
虽然后两种的方法原型返回值的类型为IEnumerable<IGrouping<K,E>>,但相比于之前的IEnumerable<IGrouping<K,T>>只不过是参数类型变了个样。而这个不同就是由第三、四种原型定义里的委托参数elementSelector造成的。当在委托keySelector返回一个类型为K的对象key,把对应于key的类型为T的元素作为一组元素之后,再依次调用委托elementSelector把序列IGrouping<K,T>中类型为T的元素转换成类型为E的元素,所以最后操作符GroupBy的返回序列的元素类型为IGrouping<K,E>。对于最后一种方法原型的实现效果其实就是第二种方法和第三种方法的合并的效果;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 //定义雇员数组 4 Employee[] employees =new Employee[] 5 { 6 new Employee{Id="0001",Name="张三",Age=32}, 7 new Employee{Id="0002",Name="李四",Age=31}, 8 new Employee{Id="0003",Name="王五",Age=32}, 9 new Employee{Id="0004",Name="小六",Age=25}, 10 new Employee{Id="0005",Name="张麻子",Age=40}, 11 new Employee{Id="0006",Name="王小二",Age=25}, 12 new Employee{Id="0007",Name="灭绝师太",Age=55}, 13 }; 14 15 //定义雇员薪水数组 16 Salary[] salarys=new Salary[] 17 { 18 new Salary{EmployeeId="0001",Wage=1700,Bonus=2500,SalaryTime=new DateTime(2011,7,15)}, 19 new Salary{EmployeeId="0002",Wage=1500,Bonus=2500,SalaryTime=new DateTime(2011,7,15)}, 20 new Salary{EmployeeId="0003",Wage=1700,Bonus=3000,SalaryTime=new DateTime(2011,7,15)}, 21 new Salary{EmployeeId="0004",Wage=1000,Bonus=2000,SalaryTime=new DateTime(2011,7,15)}, 22 new Salary{EmployeeId="0005",Wage=2000,Bonus=4000,SalaryTime=new DateTime(2011,7,15)}, 23 new Salary{EmployeeId="0006",Wage=1000,Bonus=2000,SalaryTime=new DateTime(2011,7,15)}, 24 new Salary{EmployeeId="0007",Wage=3000,Bonus=5000,SalaryTime=new DateTime(2011,7,15)}, 25 new Salary{EmployeeId="0001",Wage=1700,Bonus=3000,SalaryTime=new DateTime(2011,8,15)}, 26 new Salary{EmployeeId="0002",Wage=1500,Bonus=3000,SalaryTime=new DateTime(2011,8,15)}, 27 new Salary{EmployeeId="0003",Wage=1700,Bonus=4000,SalaryTime=new DateTime(2011,8,15)}, 28 }; 29 30 //GroupBy第一个原型 31 Console.WriteLine("调用GroupBy操作符第一个方法原型:"); 32 Console.WriteLine("------------------------------------"); 33 34 var list2 = employees.GroupBy(e => e.Age); 35 36 Console.WriteLine("按年龄分组:"); 37 foreach (var g in list2) 38 { 39 Console.WriteLine("年龄为{0}:",g.Key); 40 //输出每一组所有的雇员 41 foreach (var e in g) 42 { 43 Console.WriteLine(e.ToString()); 44 } 45 } 46 47 Console.WriteLine("***************************************************"); 48 49 //GroupBy第二个原型 50 Console.WriteLine("调用GroupBy操作符第二个方法原型:"); 51 Console.WriteLine("------------------------------------"); 52 53 //生成一个发薪时间比较类的辅助对象 54 SalayTimeComparer stc =new SalayTimeComparer(); 55 56 var list3 = salarys.GroupBy(s=>s.SalaryTime,stc); 57 58 Console.WriteLine("按分发薪水时间分组:"); 59 foreach (var g in list3) 60 { 61 Console.WriteLine("时间在{0}:", g.Key); 62 //输出每一组所有薪水情况 63 foreach (var s in g) 64 { 65 Console.WriteLine(s.ToString()); 66 } 67 } 68 69 Console.WriteLine("***************************************************"); 70 71 //GroupBy第三个原型 72 Console.WriteLine("调用GroupBy操作符第三个方法原型:"); 73 Console.WriteLine("------------------------------------"); 74 75 var list4 = employees.GroupBy(e => e.Age, e =>new { Name = e.Name }); 76 77 Console.WriteLine("按年龄分组:"); 78 foreach (var g in list4) 79 { 80 Console.WriteLine("年龄为{0}:", g.Key); 81 //输出每一组所有的雇员姓名 82 foreach (var e in g) 83 { 84 Console.WriteLine(e); 85 } 86 } 87 88 Console.WriteLine("***************************************************"); 89 90 //GroupBy第四个原型 91 Console.WriteLine("调用GroupBy操作符第四个方法原型:"); 92 Console.WriteLine("------------------------------------"); 93 94 //生成一个发薪时间比较类的辅助对象 95 SalayTimeComparer stc1 =new SalayTimeComparer(); 96 97 var list5 = salarys.GroupBy(s => s.SalaryTime, s =>new {Wage=s.Wage,Bonus=s.Bonus,SalaryTime=s.SalaryTime}, stc1); 98 99 Console.WriteLine("按分发薪水时间分组:"); 100 foreach (var g in list5) 101 { 102 Console.WriteLine("时间在{0}:", g.Key); 103 //输出每一组所有薪水情况(工资,奖金以及发薪时间) 104 foreach (var s in g) 105 { 106 Console.WriteLine(s); 107 } 108 } 109 110 Console.Read(); 111 112 }
结果(1):
结果(2):
17.Distinct操作符
(1)作用:用于把输入序列中重复的元素作为一个元素;
(2)方法原型:
public static IEnumerable<T> Distinct<T>(
this IEnumerable<T> source);
(3)原型说明:调用操作符Distinct时,系统检测每一个输入元素是否有相同的,如果有相同的元素则作为一个元素添加到结果序列中;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 Console.WriteLine("调用Distinct操作符:"); 4 Console.WriteLine("------------------------------------"); 5 6 //定义数组 7 char[] ch_array=newchar[]{'A','B','C','D','E'}; 8 char[] ch_array1=newchar[]{'A','B','C','D','E','F','G','H','I','J'}; 9 10 var items = ch_array.Concat(ch_array1); 11 12 Console.WriteLine("序列中所有元素:"); 13 foreach (var i in items) 14 { 15 Console.Write(i+""); 16 } 17 18 Console.WriteLine(); 19 20 var items1 = items.Distinct(); 21 22 Console.WriteLine("除去序列中的重复元素:"); 23 foreach (var i in items1) 24 { 25 Console.Write(i +""); 26 } 27 28 Console.Read(); 29 30 }
结果:
18.Union操作符
(1)作用:用于将两个输入序列中的元素合并成一个新的序列,且新序列中自动去除重复的序列;
(2)方法原型:
public static IEnumerable<T> Distinct<T>(
this IEnumerable<T> first
IEnumerable<T> second);
(3)原型说明:合并输入序列first和second成新的序列,且去除序列中重复的元素;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 //定义数组 4 char[] ch_array=newchar[]{'A','B','C','D','E'}; 5 char[] ch_array1=newchar[]{'A','B','C','D','E','F','G','H','I','J'}; 6 7 Console.WriteLine("调用Union操作符:"); 8 Console.WriteLine("------------------------------------"); 9 10 var items2 = ch_array.Union(ch_array1); 11 12 Console.WriteLine("序列中所有元素:"); 13 foreach (var i in items2) 14 { 15 Console.Write(i +""); 16 } 17 18 Console.Read(); 19 }
结果:
19.Intersect操作符
(1)作用:用于将两个序列中相同的元素挑选出来组成一个新的序列,相当于数学中集合的交集作用;
(2)方法原型:
public static IEnumerable<T> Intersect<T>(
this IEnumerable<T> first
IEnumerable<T> second);
(3)原型说明:将输入序列first和second中的相同元素选取出来,组成一个新的序列并返回;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 //定义数组 4 char[] ch_array=newchar[]{'A','B','C','D','E'}; 5 char[] ch_array1=newchar[]{'A','B','C','D','E','F','G','H','I','J'}; 6 7 Console.WriteLine("调用Intersect操作符:"); 8 Console.WriteLine("------------------------------------"); 9 10 var items3 = ch_array.Intersect(ch_array1); 11 12 Console.WriteLine("序列中的相同元素:"); 13 foreach (var i in items3) 14 { 15 Console.Write(i +""); 16 } 17 18 Console.Read(); 19 }
结果:
20.Except操作符
(1)作用:用于除去第一个输入序列中的那些和第二个输入序列中相同的元素,第一序列中剩余的元素组成新序列;
(2)方法原型:
public static IEnumerable<T> Except<T>(
this IEnumerable<T> first
IEnumerable<T> second);
(3)原型说明:相当于数学中的集合之间的减法运算;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 //定义数组 4 char[] ch_array=newchar[]{'A','B','C','D','E'}; 5 char[] ch_array1=newchar[]{'A','B','C','D','E','F','G','H','I','J'}; 6 7 Console.WriteLine("调用Except操作符:"); 8 Console.WriteLine("------------------------------------"); 9 10 var items4 = ch_array1.Except(ch_array); 11 12 Console.WriteLine("除去ch_array1序列中与序列ch_array里相同的元素,除去后新序列的所有元素:"); 13 foreach (var i in items4) 14 { 15 Console.Write(i +""); 16 } 17 18 Console.Read(); 19 }
结果:
21.Cast操作符
(1)作用:用于将一个类型为IEnumerable的集合对象转化为一个类型为IEnumerable<T>的集合对象;
(2)方法原型:
public static IEnumerable<T> Cast<T>(
this IEnumerable source);
(3)原型说明:从Cast操作符的方法原型可以发现它是一个在应用在类型为IEnumerable的实例对象上的扩展方法。之前也说到过,IEnumerable<T>是泛型接口,而泛型是C#2.0中才出现的,所以很多C#1.0中的一些集合类型都只是实现IEnumerable接口,比如ArrayList集合,而没有实现IEnumerable<T>接口。因为绝大部分的操作符都是针对IEnumerable<T>类型进行操作的扩展方法,所以定义在IEnumerable<T>类型上的扩展方法是无法用在这些集合类型上的,而Cast操作符就是来解决这个问题的。但需要注意的是在转化之前必须确定source中要转化的元素可以安全的转化成T类型的元素,否则系统将抛出异常;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 Console.WriteLine("调用Cast操作符:"); 4 Console.WriteLine("------------------------------------"); 5 6 //声明一个ArrayList对象 7 ArrayList empolyeelist =new ArrayList() 8 { 9 new Employee{Id="0001",Name="张三",Age=32}, 10 new Employee{Id="0002",Name="李四",Age=31}, 11 new Employee{Id="0003",Name="王五",Age=32}, 12 new Employee{Id="0004",Name="小六",Age=25}, 13 new Employee{Id="0005",Name="张麻子",Age=40}, 14 new Employee{Id="0006",Name="王小二",Age=25}, 15 new Employee{Id="0007",Name="灭绝师太",Age=55}, 16 }; 17 18 IEnumerable<Employee> list6= empolyeelist.Cast<Employee>(); 19 20 Console.WriteLine("把IEnumerable类型的集合转化为IEnumerable<T>类型的集合:"); 21 foreach (var e in list6) 22 { 23 Console.WriteLine(e); 24 } 25 26 Console.Read(); 27 }
结果:
22.OfType操作符
(1)作用:用于将一个类型为IEnumerable的集合对象转化为一个类型为IEnumerable<T>的集合对象;
(2)方法原型:
public static IEnumerable<T> OfType<T>(
this IEnumerable source);
(3)原型说明:OfType操作符的原型定义和操作符Cast一样,并且方法的实现也基本相同,唯一不同的是Cast操作符将输入的元素转换成类型为T的元素,如果转换中出现转化失败的情况,则Cast操作符会抛出一个异常,而OfTyoe操作符只是把能够转换的元素转换掉,并把这些元素添加到结果序列中去。由此看来OfType操作符比Cast操作符在使用上更加安全;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 Console.WriteLine("调用OfType操作符:"); 4 Console.WriteLine("------------------------------------"); 5 6 //声明一个ArrayList对象 7 ArrayList empolyee_salary_list =new ArrayList() 8 { 9 new Employee{Id="0001",Name="张三",Age=32}, 10 new Employee{Id="0002",Name="李四",Age=31}, 11 new Employee{Id="0003",Name="王五",Age=32}, 12 new Employee{Id="0004",Name="小六",Age=25}, 13 new Employee{Id="0005",Name="张麻子",Age=40}, 14 new Salary{EmployeeId="0001",Wage=1700,Bonus=2500,SalaryTime=new DateTime(2011,7,15)}, 15 new Salary{EmployeeId="0002",Wage=1500,Bonus=2500,SalaryTime=new DateTime(2011,7,15)}, 16 new Salary{EmployeeId="0003",Wage=1700,Bonus=3000,SalaryTime=new DateTime(2011,7,15)}, 17 }; 18 19 var list7 = empolyee_salary_list.OfType<Employee>(); 20 21 Console.WriteLine("把ArrayList类型集合转化为IEnumerable<Employee>类型的集合:"); 22 foreach (var e in list7) 23 { 24 Console.WriteLine(e); 25 } 26 27 var list8 = empolyee_salary_list.OfType<Salary>(); 28 29 Console.WriteLine("把ArrayList类型集合转化为IEnumerable<Salary>类型的集合:"); 30 foreach (var e in list8) 31 { 32 Console.WriteLine(e); 33 } 34 35 Console.Read(); 36 }
结果:
23.AsEnumerable操作符
(1)作用:用于将一个实现了IEnumerable<T>接口的对象(该对象还实现了其他接口)转换成一个标准的IEnumerable<T>接口对象;
(2)方法原型:
public static IEnumerable<T> AsEnumerable<T>(
this IEnumerable<T> source);
(3)原型说明:在LINQ中,不同领域的LINQ实现都有对应自己领域的操作符,这些领域里的操作符一般既实现个IEnumerable<T>接口,又实现了其他类型的接口,比如Linq To SQL领域中的操作符就是定义在IQueryable<T>接口上的扩展方法。所以当在IQueryable<T>对象上调用操作符Where时,被调用的操作符Where并不是定义在IEnumerable<T>接口类型上的那个Where操作符,而是调用定义在IQueryable<T>接口类型上的Where操作符,所以想要调用定义在IEnumerable<T>接口类型上的那个Where操作符的话,就需要用到AsEnumerable操作符来进行转换了;
(4)示例验证:
①实体类Student:
②调用操作符AsEnumerable:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 Console.WriteLine("调用AsEnumerable操作符:"); 4 Console.WriteLine("------------------------------------"); 5 6 //建立StudentDataContext对象用于和数据库通信 7 StudentDataContext sdc =new StudentDataContext(); 8 9 var students = (from s in sdc.students 10 select s).AsEnumerable().Reverse(); 11 12 Console.WriteLine("把一个IQueryable<T>类型的序列转换成类型为IEnumerable<T>的序列:"); 13 foreach (var stu in students) 14 { 15 Console.WriteLine("{Name="+stu.sname+"}"); 16 } 17 18 Console.Read(); 19 }
③结果(Reverse操作符是定义在IEnumerable<T>接口上的扩展方法,如果不先调用操作符AsEnumerable进行转换的话,系统将会抛出异常):
24.DefaultIfEmpty操作符
(1)作用:用来为一个空的输入序列生成一个对应的含有默认元素的新序列;
(2)方法原型:
①原型定义:
public static IEnumerable<T> DefaultIfEmpty<T>(
this IEnumerable<T> source);
②原型定义:
public static IEnumerable<T> DefaultIfEmpty<T>(
this IEnumerable<T> source,
T defaultValue);
(3)原型说明:第一种方法原型接受一个类型为IEnumerable<T>的输入序列source,如果序列为空,则生成一个新的包含默认元素的序列,元素类型必须与输入序列中的元素类型一样,若输入序列中的元素类型为引用类型,则生成的默认元素为null,若为值类型,则生成的默认元素为相应类型的默认值。第二种方法相比于第一种,区别在于它允许开发人员自己来定义类型为T的默认值(defaultValue)。也许读者会问为什么序列不能为空呢?实际上有些操作符在空序列上操作会抛出一个异常,比如操作符First;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 //定义数组 4 char[] ch_array=newchar[]{'A','B','C','D','E'}; 5 6 //DefaultIfEmpty第一个原型 7 Console.WriteLine("调用DefaultIfEmpty操作符第一个方法原型:"); 8 Console.WriteLine("------------------------------------"); 9 10 var ch = ch_array.Where(c=>c=='Z').DefaultIfEmpty().First(); 11 12 Console.WriteLine("取序列中的第一个元素:"); 13 Console.WriteLine(ch); 14 15 16 Console.WriteLine("***************************************************"); 17 18 //DefaultIfEmpty第二个原型 19 Console.WriteLine("调用DefaultIfEmpty操作符第二个方法原型:"); 20 Console.WriteLine("------------------------------------"); 21 22 var ch1 = ch_array.Where(c => c =='Z').DefaultIfEmpty('空').First(); 23 24 Console.WriteLine("取序列中的第一个元素:"); 25 Console.WriteLine(ch1); 26 27 Console.Read(); 28 }
结果:
25.Range操作符
(1)作用:用于辅助生成一个整数序列;
(2)方法原型:
public static IEnumerable<int> Range(
int start,
int count);
(3)原型说明:操作符Range的方法原型并不是一个扩展方法,只是定义在System.Linq.Enumerable命名空间里的一个普通的静态方法。参数start表示整数序列开始的数值,而参数count表示序列元素的个数,最后返回类型为IEnumerable<int>的序列;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 Console.WriteLine("调用Range操作符:"); 4 Console.WriteLine("------------------------------------"); 5 6 IEnumerable<int> int_sequences = Enumerable.Range(1, 10); 7 8 Console.WriteLine("整数序列:"); 9 foreach (var i in int_sequences) 10 { 11 Console.Write(i +""); 12 } 13 14 Console.Read(); 15 }
结果:
26.Repeat操作符
(1)作用:用于生成一个指定数量重复元素的序列;
(2)方法原型:
public static IEnumerable<T> Repeat<T>(
T element,
int count);
(3)原型说明:同样操作符Repeat也只是定义在System.Linq.Enumerable命名空间里的一个普通的静态方法,参数element表示要重复元素,类型为T,参数count表示重复次数,最后返回类型为IEnumerable<T>的序列;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 Console.WriteLine("调用Repeat操作符:"); 4 Console.WriteLine("------------------------------------"); 5 6 IEnumerable<string> items5 = Enumerable.Repeat("LINQ", 3); 7 8 Console.WriteLine("重复字符串LINQ三次:"); 9 foreach (var str in items5) 10 { 11 Console.Write(str +""); 12 } 13 14 Console.Read(); 15 }
结果:
27.Empty操作符
(1)作用:用于生成一个包含指定类型元素的空序列;
(2)方法原型:
public static IEnumerable<T> Empty<T>( );
(3)原型说明:操作符Empty也只是定义在System.Linq.Enumerable命名空间里的一个普通的静态方法,其返回一个元素类型为T的序列IEnumerable<T>;
(4)示例验证:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 staticvoid Main(string[] args) 2 { 3 Console.WriteLine("调用Empty操作符:"); 4 Console.WriteLine("------------------------------------"); 5 6 var list9 = Enumerable.Empty<Employee>().DefaultIfEmpty(); 7 8 Console.WriteLine("生成一个元素类型为Employee的空序列(默认值为null):"); 9 foreach (var e in list9) 10 { 11 Console.Write(e); 12 } 13 14 Console.Read(); 15 }
结果: