Linq学习之旅——Linq to Objects之延期执行方法(下篇)
2012-07-29 22:18 xiashengwang 阅读(1155) 评论(1) 编辑 收藏 举报目录
本篇继续学习剩余的延期执行方法。
1,Intersect 方法
Intersect 方法用于生成两个序列的交集。
string[] names = { "郭靖", "李莫愁", "欧阳晓晓", "黄蓉", "黄药师" }; string[] names2 = { "郭靖", "杨过", "欧阳晓晓" }; Console.WriteLine("相交的元素"); foreach (var name in names.Intersect(names2)) { Console.Write(name + " "); }
输出结果:
相交的元素
郭靖 欧阳晓晓
自定义IEqualityComparer<T>
public class MyEqualityComparer<T> : IEqualityComparer<T> { #region IEqualityComparer<T> 成员 public bool Equals(T x, T y) { string temp = x as string; if (temp != null) { if (temp == "欧阳晓晓") //对"欧阳晓晓"不过滤 return false; } if (x.GetHashCode() == y.GetHashCode()) return true; else return false; } public int GetHashCode(T obj) { return obj.GetHashCode(); } #endregion }
string[] names = { "郭靖", "李莫愁", "欧阳晓晓", "黄蓉", "黄药师" }; string[] names2 = { "郭靖", "杨过", "欧阳晓晓" }; Console.WriteLine("相交的元素"); foreach (var name in names.Intersect(names2,new MyEqualityComparer<string>())) { Console.Write(name + " "); }
输出结果:
相交的元素
郭靖
2,Except 方法
Except 方法用于生成两个序列的差集。
注意:返回是第一个数组里,去掉指定数组里的元素后,剩下的一个序列。
它和Intersect方法不是互补的,不要搞混了。下面的“杨过”就不会输出。因为它是指定数组里的元素,和源数组一毛钱关系都没有。
string[] names = { "郭靖", "李莫愁", "欧阳晓晓", "黄蓉", "黄药师" }; string[] names2 = { "郭靖", "杨过", "欧阳晓晓" }; Console.WriteLine("2个数组的不同元素"); foreach (var name in names.Except(names2)) { Console.Write(name + " "); }
输出结果:
2个数组的不同元素
李莫愁 黄蓉 黄药师
运用自定义IEqualityComparer<T>指定比较器。
string[] names = { "郭靖", "李莫愁", "欧阳晓晓", "黄蓉", "黄药师" }; string[] names2 = { "郭靖", "杨过", "欧阳晓晓" }; Console.WriteLine("2个数组的不同元素"); foreach (var name in names2.Except(names,new MyEqualityComparer<string>())) { Console.Write(name + " "); }
输出结果:
2个数组的不同元素
杨过 欧阳晓晓
3,Range 方法
Range 方法用于生成指定范围的整数序列。在BS程序中,经常需要分页显示,在页面中需要显示页面号码的链接,用这个方法可以生成页码的数组。
由于没有this关键字,它是一个普通的静态方法。
int istart = 1;//起始页码 int iend = 12; //结束页码 var pages = Enumerable.Range(1, iend - istart + 1); Console.WriteLine("输出页码"); foreach (var n in pages) { Console.Write("[{0}] ", n); }
输出结果:
输出页码 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12]
4,Repeat 方法
Repeat 方法用于生成指定数量重复元素的序列。由于没有this关键字,它是一个普通的静态方法。
var people = new { Name = "郭靖", Age = 35 };//定义一个匿名类型 var peoples = Enumerable.Repeat(people, 4); Console.WriteLine("包含4个匿名元素:"); foreach (var n in peoples) { Console.WriteLine("{0} {1} ", n.Name, n.Age); }
输出结果:
包含4个匿名元素: 郭靖 35 郭靖 35 郭靖 35 郭靖 35
5,Empty 方法
Empty 方法用于获取一个指定类型参数的空序列。由于没有this关键字,它是一个普通的静态方法。
var s = Enumerable.Empty<string>(); Console.WriteLine("序列的元素数:{0} ", s.Count());
输出结果:
序列的元素数:0
6,DefaultIfEmpty 方法
DefaultIfEmpty 方法用于获取序列,如果序列为空则添加一个类型的默认值。例如:如果元素为引用类型,添加null元素;元素为int类型,则添加int的默认值0。
string[] names = { "郭靖", "李莫愁", "欧阳晓晓", "黄蓉", "黄药师" }; var intempty = Enumerable.Empty<int>();//空的Int类型序列 //没有找到元素的序列 var empty = from n in names where n.Length == 5 select n; Console.WriteLine("DefaultIfEmpty 返回有内容的序列"); foreach (var n in names) { Console.Write("{0} ", n); } Console.WriteLine("\nempty空序列元素数:{0}", empty.Count()); Console.WriteLine("empty空序列应用DefaultIfEmpty 后的元素数:{0}", empty.DefaultIfEmpty().Count()); Console.Write("empty空序列应用DefaultIfEmpty 后的元素值:"); foreach (var n in empty.DefaultIfEmpty()) { if (n == null) Console.Write("null"); } Console.WriteLine("\n****************************************"); Console.WriteLine("intempty空序列元素数:{0}", intempty.Count()); Console.WriteLine("intempty空序列应用DefaultIfEmpty 后的元素数:{0}", intempty.DefaultIfEmpty().Count()); Console.Write("intempty空序列应用DefaultIfEmpty 后的元素值:"); foreach (var n in intempty.DefaultIfEmpty()) { Console.Write(n); }
输出结果:
DefaultIfEmpty 返回有内容的序列 郭靖 李莫愁 欧阳晓晓 黄蓉 黄药师 empty空序列元素数:0 empty空序列应用DefaultIfEmpty 后的元素数:1 empty空序列应用DefaultIfEmpty 后的元素值:null **************************************** intempty空序列元素数:0 intempty空序列应用DefaultIfEmpty 后的元素数:1 intempty空序列应用DefaultIfEmpty 后的元素值:0
这个方法还可以指定一个自定义的默认值。
var intempty = Enumerable.Empty<int>();//空的Int类型序列 Console.Write("int 类型自定义默认值:"); foreach (var i in intempty.DefaultIfEmpty(200)) { Console.Write(i); }
输出结果:
int 类型自定义默认值:200
7,Cast 方法
Cast 方法用于按照TResult类型转换IEnumerable序列的集合。
//ArrayList没有实现IEnumerable<T>接口 ArrayList names = new ArrayList(); names.Add("郭靖"); names.Add("李莫愁"); names.Add("欧阳晓晓"); IEnumerable<string> newNames = names.Cast<string>(); foreach (var s in newNames) { Console.WriteLine(s); }
输出结果:
郭靖
李莫愁
欧阳晓晓
8,OfType 方法
OfType 方法用于根据TResult类型筛选IEnumerable类型序列的元素。它的用途和Cast方法类似,但OfType方法如果遇到不能强制转换成TResutl的类型,会丢弃该元素,而不会出现运行错误。
//ArrayList没有实现IEnumerable<T>接口 ArrayList names = new ArrayList(); names.Add("郭靖"); names.Add("李莫愁"); names.Add(100); names.Add(new Stack()); names.Add("欧阳晓晓"); IEnumerable<string> newNames = names.OfType<string>(); foreach (var s in newNames) { Console.WriteLine(s); }
输出结果:
郭靖
李莫愁
欧阳晓晓
9,AsEnumerable方法
AsEnumerable方法根据元素的类型转换为泛型IEnumerable<T>类型。
MSDN上的一个例子,AsEnumerable用于隐藏自己定义的和IEnumerable里的扩展方法同名的方法。
public class MyList<T> : List<T> { public IEnumerable<T> Where(Func<T, bool> predicate) { Console.WriteLine("In MyList of Where"); return Enumerable.Where(this, predicate); } } private void AsEnumerableDemo() { MyList<string> list = new MyList<string>() { "郭靖", "黄蓉", "黄药师" }; var query1 = list.Where(n => n.Contains("郭")); Console.WriteLine("query1 created"); var query2 = list.AsEnumerable().Where(n => n.Contains("郭")); Console.WriteLine("query2 created"); }
运行结果:
In MyList of Where
query1 created
query2 created
AsEnumerable方法经常用于Linq To SQL查询,将IQueryable<T>转换成IEnumerable<T>接口。因为一些扩展方法,如Reverse等,虽然在IQueryable<T>里有定义,但并不能将其翻译成对应的SQL语句,所以运行时会报错。用AsEnumerable方法转换成IEnumerable<T>后,实际的数据就在内存中操作。关于IQueryable<T>调用AsEnumerable背后的转换本质,有待进一步考证。