代码改变世界

Linq学习之关键字

2012-06-25 19:42  Shawn.Cheng  阅读(2526)  评论(1编辑  收藏  举报

 

书写Linq时,分为方法语法和查询表达式两种语法方式。

这里假设你对Lambda表达式,匿名类型,静态扩展方法 有一定的认识。

以下,对Linq中的部分关键字进行介绍。

学习过程中,主要参考了 http://www.cnblogs.com/goscan/archive/2011/05/05/Linq_study_log.html 一文,在这里表示对作者进行感谢。

From关键字 

使用From时,From后跟数据源的一个变量,in 后指定数据源。数据源的类型必须是实现IEnumerable<T>,如果仅仅实现了IEnumerable类型可以通过Cast<T>方法来转换

示例代码

 1         //from 的Container必须是IEnumerable<T> 类型
 2         public void StudyFrom()
 3         {
 4 
 5             //IEnumerable<BookMarker> query = from bm in Container select bm;
 6             string[] array = new string[] { "fa", "dsfsa", "fdsaf" };
 7             IEnumerable<string> res = from s in array select s;//数组可以
 8             ArrayList al = new ArrayList() { "fds", "dsaf", "fdsa" };//ArrayList并没有实现IEnumerable<T>
 9             IEnumerable<string> data = al.Cast<string>();//可以转换为IEnumerable<T>类型
10         }

 

Select关键字

Select可以看做事对查询结果的投影,类似与SQL中查询出来的新表,在这里是新的对象。

可以对新的对象进行重组(查询结果的投影),生成新的对象。

示例代码

        //select 是对查询结果的投影
        //
        public void StudySelect()
        {
            //将结果投影到一个匿名类型上
            var bs = from p in Container select new { p.Name, p.Value };
            //将投影结果进行计算重组
            var bs2 = from b in Container
                      select new
                                 {
                                     Name = b.Name,
                                     Tag = b.Category + "$" + b.Tag
                                 };
            var bs3 = Container.Select(p => new { Name = p.Name, Tag = p.Category + "$" + p.Tag });//利用Lambda查询
        }

 

 

Join关键字

Join关键字稍显复杂。格式如下

 From a in aSet join b in bSet  on a.ID equals b.ID select new{a,b}

 或者

From a in aSet join b in bSet on value1 equals value2 select *****

或者

 From a in aSet join b in bSet on Func1() equals Func2() select ***

方法语法的格式为

aSet.Join(bSet , 获得判等左值的委托,获得判等右值的委托,查询结果投影委托 )

例如 aSet.Join(bSet,a=>a.ID,b=>b.ID,(a,b)=>new {a,b})

示例代码

 

        /// <summary>
        /// Join方法 from a in aSet join b in bSet on a.Id equals b.Id select new { a,b}
        /// from a in aSet join b in bSet on value1 equals value2 ……
        /// from a in aSet join b in bSet on Func1() equals
        /// 操作符号需要是equals 或者not equals 
        /// Join方法 ( 第二个需要连接的数据源,表达式1,表达式2,输出结果 ) 表达式1会默认和表达式2相等最为连接条件
        /// </summary>
        public void StudyJoin()
        {
            string[] indexs = new string[] { "1", "2", "6", "9" };
            var res = from i in indexs
                      join b in Container
                          on "ID-" + i equals b.ID
                      select new string[] { i, b.Name };
            foreach (string[] strings in res)
            {
                Console.WriteLine(string.Format("index->{0},value-{1}", strings[0], strings[1]));
            }

            var res2 = indexs.Join(Container, i => "ID-" + i, c => c.ID, (i, c) => new { i, c });//函数式查询
            foreach (var item in res2)
            {
                Console.WriteLine(item.i + "==>" + item.c.Name);
            }
        }

 

 

Group关键字

Group关键字表示对数据源进行分组,使用GroupBy组合,Group后跟数据源,by后跟分组依据,into 表示将分组结果存放到的变量,该变量会默认有一个Key属性,即为by 的依据(组别),该变量类型是IGrouping<TKey,TElement>类型,所以查出来就是IGrouping的一个集合。如果想要访问其中的元素,需要使用两层ForEach进行遍历。

示例代码

 

        /// <summary>
        /// Group将对查询结果进行分组,使用Group By 组合,group后边跟为哪个对象分组,by后边跟上分组的依据
        /// 分组完成需要使用into将分组后的结果放在一个变量中
        /// 访问该变量的Key属性可以得到组别
        /// </summary>
        public void StudyGroup()
        {
            var res = from bookMarker in Container
                      group bookMarker by bookMarker.ID.Length
                          into bg
                          select new { bg.Key, bg };
            
            res.ToList().ForEach
                (
                    item =>
                        {
                            Console.WriteLine(string.Format("Key:{0},----", item.Key));
                            item.bg.ToList().ForEach(
                                bookmarker => Console.WriteLine(string.Format("ID:{0},Name:{1}", bookmarker.ID, bookmarker.Name)));
                        }

                );
        }

Let关键字

Let关键字允许在查询过程中,自定一个一个变量,供使用。

示例代码

 

        /// <summary>
        /// let运行在查询过程中,自定义一个变量,供使用
        /// </summary>
        public void StudyLet()
        {
            var query = from bookmarker in Container
                        let Type = "书签"
                        select new
                                   {
                                       Type = Type,
                                       Name = bookmarker.Name,
                                       Url = bookmarker.Value
                                   };
            foreach (var VARIABLE in query)
            {
                Console.WriteLine(string.Format("书签名{0},地址是{1}。类型为{2}", VARIABLE.Name, VARIABLE.Url, VARIABLE.Type));
            }
        }

 

Take和Skip关键字

Skip表示跳过集合的若干个元素,Take表示从当前集合的开始处取N个元素

示例

        public void StudyTakeSkip()
        {
            var query = from bookmarker in Container select bookmarker;
           IEnumerable<BookMarker> source=   query.Skip(2).Take(6);
            Printer<BookMarker>.ConPrint( source, item=>string.Format( "名字:{0}ID:{1}",item.Name,item.ID ) );
        }

 

Yield关键字

Yield关键字可以使得查询延迟加载。也就是在使用到该数据时,在进行数据的添加或者访问。但是如果使用了聚合函数,例如MAX,OrderBy,等,该特性竟会失效,将遍历所有元素。

示例代码

将会发生死循环。

        //LazyLoad示例

        //yield 关键字可以使得 查询时延迟加载,即使用是再向数据容器中添加数据
        public static  IEnumerable<int> InitData()
        {
            int i = 0;
            while (true)
            {
                yield return i++;
            }
        }


        public void LazyLoad()
        {
            var query = from i in InitData() select i;
            Printer<int>.ConPrint(query.Take(10),item=>item.ToString());
        }

        public void CannotLazyLoad()
        {
            var query = from i in InitData() select i;
            Printer<int>.ConPrint(query.OrderBy(item=>item).Take(10),item=>item.ToString());//使用OrderBy时,会尝试遍历所有元素,故会无限循环

        }

 

之下是DataContainer.cs

    public class DataContainer
    {
        public static List<BookMarker> BookMarkers { get; set; } 

       static DataContainer()
        {
            InitBookMarkers();
        }

        static private void InitBookMarkers()
        {
            BookMarkers=new List<BookMarker>();
            for (int i = 0; i < 20; i++)
            {
                BookMarker b=new BookMarker()
                                 {
                                     ID = string.Format("ID-{0}",i),
                                     Name = string.Format("Name-{0}",i),
                                     Category = string.Format("Category-{0}",i),
                                     Tag = string.Format("Tag-{0}",i),
                                     Value=string.Format("Value-{0}",i)
                                 };
                BookMarkers.Add(b);
            }
            
        }
    }

    public class  BookMarker
    {
        public string Name { get; set; }
        public string ID { get; set; }
        public string Category { get; set; }
        public string Tag { get; set; }
        public string Value { get; set; }
    }

 

 Printer.cs

    public class Printer<T>
    {
        public static void ConPrint<T>(IEnumerable<T> source,Func<T,string> toStrFunc  )
        {
            foreach (T t in source)
            {
                Console.WriteLine( toStrFunc(t) );
            }
        }
    }

Program.cs

        static void Main(string[] args)
        {
            KeyWordsStudy keyWordsStudy=new KeyWordsStudy();
            //keyWordsStudy.StudyJoin();
            //keyWordsStudy.StudyLet(); 
            keyWordsStudy.StudyGroup();
            keyWordsStudy.StudyTakeSkip();
            //keyWordsStudy.LazyLoad();
            //keyWordsStudy.CannotLazyLoad();会抛出内存溢出的异常,应为orderby的存在,导致 试图遍历所有成员//Console.WriteLine("结束");
            Console.ReadKey();

        }