雁过请留痕...
代码改变世界

Linq学习之旅——Linq to Objects之延期执行方法(下篇)

2012-07-29 22:18  xiashengwang  阅读(1145)  评论(1编辑  收藏  举报

目录

1,Intersect 方法

2,Except 方法

3,Range 方法

4,Repeat 方法

5,Empty 方法

6,DefaultIfEmpty 方法

7,Cast 方法

8,OfType 方法

9,AsEnumerable方法

    本篇继续学习剩余的延期执行方法。

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背后的转换本质,有待进一步考证。