[转载]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();
}
Mikel