[转载]Linq学习之关键字 – line.cheng – 博客园.
书写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>方法来转换
示例代码
//from 的Container必须是IEnumerable<T> 类型 public void StudyFrom() { //IEnumerable<BookMarker> query = from bm in Container select bm; string[] array = new string[] { "fa", "dsfsa", "fdsaf" }; IEnumerable<string> res = from s in array select s;//数组可以 ArrayList al = new ArrayList() { "fds", "dsaf", "fdsa" };//ArrayList并没有实现IEnumerable<T> IEnumerable<string> data = al.Cast<string>();//可以转换为IEnumerable<T>类型 }
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
示例代码
/// <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(); }