议程
1.LINQ和LINQ表达式
2.Lambda表达式
两个接口
IEnumerable <T> 泛型接口
公开枚举数,该枚举数支持在指定类型的集合上进行简单迭代。
public class MyCollections<T> : IEnumerable<T>
{
T[] values = new T[100];
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < 100; i++)
{
yield return values[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class Class2
{
static void Main()
{
MyCollections<int> Mycol = new MyCollections<int>();
foreach (int i in Mycol)
{
Console.WriteLine(i);
}
}
}
Iqueryable<T>
提供对数据类型已知的特定数据源的查询进行计算的功能。
此接口继承 IEnumerable<T>接口,因此,如果它表示一个查询,则可以枚举该查询的结果。枚举强制执行与 Iqueryable<T>对象关联的表达式目录树。
LINQ基本概念
LINQ:语言集成查询(Language Integrated Query),是一系列标准查询操作符的集合,这些操作符几乎对每一种数据源的导航,过滤和执行都是提供了底层的基本查询架构。
LINQ可查的数据源包括关系数据,XML,DataSet或内存中的数据。
LINQ出现的背景:大多数开发人员对OO的熟悉,最好提把对数据的操作转化成对对象的操作。
LINQ恰好将标准查询功能直接整合到了供开发人员选择的基于.NET的编程语言中。
LINQ支术的重点是查询表达式,因为它描述了对数据源的具体操作。
LINQ查询表达式基本概念
1.查询表达式可用于查询和转换来自任意支持 LINQ 的数据源中的数据。例如,单个查询可以从 SQL 数据库检索数据,并生成 XML 流作为输出。
2.查询表达式容易掌握,因为它们使用许多常见的 C# 语言构造。
3.查询表达式中的变量都是强类型的,但许多情况下您不需要显式提供类型,因为编译器可以推断类型。
4.在您循环访问 foreach 语句中的查询变量之前,不会执行查询。
5.在编译时,根据 C# 规范中设置的规则将查询表达式转换为“标准查询运算符”方法调用。任何可以使用查询语法表示的查询也可以使用方法语法表示。但是,在大多数情况下,查询语法更易读和简洁。
6.作为编写 LINQ 查询的一项规则,建议尽量使用查询语法,只在必需的情况下才使用方法语法。这两种不同形式在语义或性能上没有区别。查询表达式通常比用方法语法编写的等效表达式更易读。
7.一些查询操作,如 Count 或 Max,没有等效的查询表达式子句,因此必须表示为方法调用。方法语法可以通过多种方式与查询语法组合。
8.查询表达式可以编译为表达式目录树或委托,具体取决于查询所应用到的类型。IEnumerable<(Of <(T>)>) 查询编译为委托。IQueryable 和 IQueryable<(Of <(T>)>) 查询编译为表达式目录树。
LINQ查询表达式
查询操作包含三部分:
- 获取数据源
- 创建查询
- 执行查询
Demo:
//获取数据源
string[] Devices= {"电视" ,"电冰箱","洗衣机","电话","微波炉"};
//创建查询
var SelectDevices = from device in Devices
where device.StartsWith("电")
select device;
//执行查询
foreach (string dev in SelectDevices)
{
Console.WriteLine("带电的设备:{0}",dev);
}
匿名方法
在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法。C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式。不过,本主题中有关匿名方法的信息同样也适用于 Lambda 表达式。有一种情况下,匿名方法提供了 Lambda 表达式中所没有的功能。匿名方法使您能够省略参数列表,这意味着可以将匿名方法转换为带有各种签名的委托。这对于 Lambda 表达式来说是不可能的。
button1.Click += delegate(System.Object o, System.EventArgs e)//匿名方法参数
{//匿名方法方法体
MessageBox.Show("Click!");
};
Lambda表达式
- “Lambda 表达式”是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。
- 所有 Lambda 表达式都使用 Lambda 运算符 =>,该运算符读为“goes to”。该 Lambda 运算符的左边是输入参数(如果有),右边包含表达式或语句块。Lambda 表达式 x => x * x 读作“x goes to x times x”。可以将此表达式分配给委托类型
static void Main()
{
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
Console.WriteLine(j);
}
delegate int del(int i);
- 只有在 Lambda 有一个输入参数时,括号才是可选的;否则括号是必需的。两个或更多输入参数由括在括号中的逗号分隔:
(x, y) => x == y
- 有时,编译器难于或无法推断输入类型。如果出现这种情况,您可以按以下示例 中所示方式显式指定类型:
(int x, string s) => s.Length > x
uLambda 语句与 Lambda 表达式类似,只是语句括在大括号中:
delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");
- 在编写 Lambda 时,通常不必为输入参数指定类型,因为编译器可以基于 Lambda 主体、基础委托类型以及 C# 3.0 语言规范中描述的其他因素推断类型。对于大多数标准查询运算符,第一个输入是源序列中的元素的类型。因此,如果要查询 IEnumerable<Customer>,则输入变量将被推断为 Customer类型,这意味着您可以访问其方法和属性:
customers.Where(c => c.City == "London");
- 有时,编译器难于或无法推断输入类型。如果出现这种情况,您可以按以下示例 中所示方式显式指定类型:
(int x, string s) => s.Length > x
uLambda 语句与 Lambda 表达式类似,只是语句括在大括号中:
delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");
- 在编写 Lambda 时,通常不必为输入参数指定类型,因为编译器可以基于 Lambda 主体、基础委托类型以及 C# 3.0 语言规范中描述的其他因素推断类型。对于大多数标准查询运算符,第一个输入是源序列中的元素的类型。因此,如果要查询 IEnumerable<Customer>,则输入变量将被推断为 Customer类型,这意味着您可以访问其方法和属性:
customers.Where(c => c.City == "London");
Lambda 的一般规则如下:
- Lambda 包含的参数数量必须与委托类型包含的参数数量相同。
- Lambda 中的每个输入参数必须都能够隐式转换为其对应的委托参数。
- Lambda 的返回值(如果有)必须能够隐式转换为委托的返回类型。
Lambda 可以引用“外部变量”,这些变量位于在其中定义 Lambda 的封闭方法或类型的范围内。将会存储通过这种方法捕获的变量以供在 Lambda 表达式中使用,即使变量将以其他方式超出范围或被作为垃圾回收。必须明确地分配外部变量,然后才能在 Lambda 表达式中使用该变量。
- 捕获的变量将不会被作为垃圾回收,直至引用变量的委托超出范围为止。
- 在外部方法中看不到 Lambda 表达式内引入的变量。
- Lambda 表达式无法从封闭方法中直接捕获 ref 或 out 参数。
- Lambda 表达式中的返回语句不会导致封闭方法返回。
- Lambda 表达式不能包含其目标位于所包含匿名函数主体外部或内部的 goto 语句、break 语句或 continue 语句。
查询语法和方法语法
string[] Devices= {"电视" ,"电冰箱","洗衣机","电话","微波炉"};
查询语法
var SelectDevices = from device in Devices
where device.StartsWith("电")
select device;
方法语法
var SelectDevices =Devices .Where ( device => device.StartsWith("电"))
foreach (string dev in SelectDevices)
{
Console.WriteLine("带电的设备:{0}",dev);
}
本文转自桂素伟51CTO博客,原文链接: http://blog.51cto.com/axzxs/195098,如需转载请自行联系原作者