LINQ
大约 9 分钟
LINQ
- LINQ:语言集成查询Language Integrated Query;
- 允许使用SQL查询数据库的方式来查询数据集合;
- 以 from... 开始,以 select... 或 group 结束
- 查询语句不会立即执行,只有在使用 foreach 遍历的时候才会执行查询
- 谓词 predicate :返回布尔值的方法
- LINQ中提供了 IEnumerable 的扩展方法,配合lambda能简化数据处理
- 大部分扩展方法都在System.Linq命名空间中
委托
- 委托是可以指向方法的类型,调用委托变量时执行的就是变量指向的方法
- .NET 中定义了泛型委托 Action(无返回值)和 Func(有返回值)
- 委托变量不仅可以指向普通方法,还可以指向匿名方法,匿名方法可以写成 lambda 表达式
匿名类型
匿名类型只能和局部变量配合使用;
变量必须使用var作为关键字;
不能设置匿名类型对象的属性,其属性是只读的;
如果编译其遇到另一个具有相同参数名、相同推断类型、相同顺序的匿名函数,则它会重用这个类型并直接创建新的实例,不会再创建新的匿名类型;
var student = {Name = "zhangshan",Age = 19}
SQL风格查询
from ... in ...
[from ... let ... where ...]
[orderby ... ]
select ...
[into ...]
from ... in ...
// 迭代变量逐个表示数据源的每一个元素
static void Main(string[] args)
{
var groupA = new[] { 4, 5, 6 };
var groupB = new[] { 6, 7, 8 };
var tmp = from a in groupA
from b in groupB
select new { a, b };
foreach (var x in tmp)
Console.WriteLine(x);
Console.ReadLine();
}
//{ a = 4, b = 6 }
//{ a = 4, b = 7 }
//{ a = 4, b = 8 }
//{ a = 5, b = 6 }
//{ a = 5, b = 7 }
//{ a = 5, b = 8 }
//{ a = 6, b = 6 }
//{ a = 6, b = 7 }
//{ a = 6, b = 8 }
where ...
static void Main(string[] args)
{
var groupA = new[] { 4, 5, 6 };
var groupB = new[] { 6, 7, 8 };
var tmp = from a in groupA
from b in groupB
where a>5 && b>7
select new { a, b };
foreach (var x in tmp)
Console.WriteLine(x);
Console.ReadLine();
}
//{ a = 6, b = 8 }
join ... in ... on ...
// 用于连接两个或更多集合中的数据
static void Main(string[] args)
{
var groupA = new[] { 4, 5, 6 };
var groupB = new[] { 6, 7, 8 };
var tmp = from a in groupA
join b in groupB on a equals b
select new { a, b };
foreach (var x in tmp)
Console.WriteLine(x);
Console.ReadLine();
}
//{ a = 6, b = 6 }
let ...
// 接受一个表达式的运算并赋值给一个标识符
static void Main(string[] args)
{
var groupA = new[] { 4, 5, 6 };
var groupB = new[] { 6, 7, 8 };
var tmp = from a in groupA
from b in groupB
where a > 5 && b>6
let sum = a+b
select new { a, b ,sum};
foreach (var x in tmp)
Console.WriteLine(x);
Console.ReadLine();
}
//{ a = 6, b = 7, sum = 13 }
//{ a = 6, b = 8, sum = 14 }
group ... by ...
// 选择数据项并分组
// group 返回的是分组的可枚举类型
static void Main(string[] args)
{
var students = new[] {
new { Name = "Tom", Age=15, Gender="Male"} ,
new { Name = "Bob", Age=14, Gender="Male"},
new { Name = "Lisa", Age=15, Gender="Female"},
new { Name = "Sari", Age=15, Gender="Female"}
};
var tmp = from student in students
group student by student.Gender;
foreach (var x in tmp)
{
Console.WriteLine(x.Key);
foreach (var s in x)
Console.WriteLine(s);
}
Console.ReadLine();
}
//Male
//{ Name = Tom, Age = 15, Gender = Male }
//{ Name = Bob, Age = 14, Gender = Male }
//Female
//{ Name = Lisa, Age = 15, Gender = Female }
//{ Name = Sari, Age = 15, Gender = Female }
orderby ...
// 按表达式顺序返回值
static void Main(string[] args)
{
var students = new[] {
new { Name = "Tom", Age=15, Gender="Male"} ,
new { Name = "Bob", Age=14, Gender="Male"},
new { Name = "Lisa", Age=15, Gender="Female"},
new { Name = "Sari", Age=13, Gender="Female"}
};
var tmp = from student in students
orderby student.Age
select student;
foreach (var x in tmp)
{
Console.WriteLine(x);
}
Console.ReadLine();
}
//{ Name = Sari, Age = 13, Gender = Female }
//{ Name = Bob, Age = 14, Gender = Male }
//{ Name = Tom, Age = 15, Gender = Male }
//{ Name = Lisa, Age = 15, Gender = Female }
into ...
// into 接受查询的一部分结果并赋予一个名字,从而可以在查询的另一部分使用
static void Main(string[] args)
{
var groupA = new[] { 4, 5, 6 };
var groupB = new[] { 6, 7, 8 };
var tmp = from a in groupA
from b in groupB
select new { a, b, sum = a + b }
into grounpAandB
where grounpAandB.sum > 12
select grounpAandB;
foreach (var x in tmp)
Console.WriteLine(x);
Console.ReadLine();
}
//{ a = 5, b = 8, sum = 13 }
//{ a = 6, b = 7, sum = 13 }
//{ a = 6, b = 8, sum = 14 }
标准查询运算符
序列:被查询的集合对象,它必须实现
IEnumerable<T>接口;
标准查询运算符声明在System.Linq.Enumerable类中,同时也是
IEnumerable<T>
泛型类的扩展方法;调用方法可以采用方法语法和扩展语法;
很多标准运算符需要使用委托类型参数:Func委托和Action委托;
Func委托有返回值,Action委托无返回值;
static void Main(string[] args) { var students = new[] { new { Name = "Tom", Age=15, Gender="Male"} , new { Name = "Bob", Age=14, Gender="Male"}, new { Name = "Lisa", Age=15, Gender="Female"}, new { Name = "Sari", Age=13, Gender="Female"} }; // 使用扩展方法 var tmp1 = students.Where(student => student.Age == 15); // 使用 Enumerable 方法 var tmp2 = Enumerable.Where(students,student => student.Gender == "Male"); foreach (var x in tmp1) { Console.WriteLine(x); } Console.WriteLine("----------------"); foreach (var x in tmp2) { Console.WriteLine(x); } Console.ReadLine(); //{ Name = Tom, Age = 15, Gender = Male } //{ Name = Lisa, Age = 15, Gender = Female } //---------------- //{ Name = Tom, Age = 15, Gender = Male } //{ Name = Bob, Age = 14, Gender = Male }
运算符名 描述 Where<br />OfType<TResult>
筛选操作符<br />对序列进行过滤
Select<br />SelectMany
投射操作符。<br />返回包含对象的的集合 <br />返回集合的集合
OrderBy / OrderByDescending<br />ThenBy / ThenByDescending<br />Reverse
排序操作符<br />ThenBy 在完成 OrderBy 后进行第二次排序<br />反转序列中的元素
Take / Skip<br />TakeWhile / SkipWhile
分区操作符<br />获取 / 跳过 序列中前n个对象<br />获取 / 跳过 提取条件位真的对象
First / FirstOrDefault<br />Last / LastOrDefault<br />ElementAt / ElementAtOrDefault<br />Single / SingleOrDefault
元素操作符<br />没有找到将抛出异常<br />Default 提供默认值时不会抛出异常
Count / LongCount<br />Sum / Min / Max<br />Average / Aggregate
聚合操作符<br />Aggregate 执行指定函数
Join<br />GroupJoin<br />Concat
连接操作符<br />对两个序列内联结<br />GroupJoin 可以产生层次结果的联结
SequenceEqual
返回bool,判断两个序列是否相等
Empty / DefaultIfEmpty / Range / Repeat
生成操作符<br />空集合 / 序列为空时的默认值 / 递增数列 / 重复元素
GroupBy / ToLookup
分组操作符
Any / All / Contains
限定操作符<br />返回序列是否 存在 / 全部 / 包含 满足条件的元素
Union / Intersect / Except / Distinct / Zip
Set 操作符<br />返回两个序列的并集 / 交集 / 差集 / 去重 / 合并
AsEnumerable / Cast<TResult><br />ToArray / ToList / ToDictionary
转换操作符
常用方法
查询
- Where:每一项数据都会经过predicate的测试,如果针对一个元素,predicate执行的返回值为true,那么这个元素就会放到返回值中。
- Any:是否至少有一条数据
获取一条数据
- Single:有且只有一条满足要求的数据,没有匹配或大于一条数据则报错
- SingleOrDefault:有且只有一条满足要求的数据,多余一条数据则返回默认值,没有匹配则报错
- First:至少有一条,返回第一条;
- FirstOrDefault :返回第一条或者默认值;
分页数据
- Skip:跳过n条数据
- Take:获取n条数据
排序
- Order / OrderByDescending:正序 / 倒序排序
- Lambda 表达式中用Guid或者随机数作为参数实现随机排序
- 对于简单数据类型排序,不需要用 lambda 表达式
- ThenBy / ThenByDescending:在Order之后使用次要字段排序
聚合函数
- Max()、Min () 、Average () 、Sum () 、Count ()
分组 GroupBy
- GroupBy() 方法返回值为 IGrouping<TKey, TSource> 类型的泛型 IEnumerable
- IGrouping 是一个继承自 IEnumerable 的接口
投影 Select
把集合中的每一项转换为另外一种类型。
参数是一个匿名类型
var items = list.Select(e=>new{Name=e.Name,Agee.Age})
LINQ to XML
XML基础
- XML:可扩展标记语言,储存和交换数据的的很重要方法;
- 标记语言:文档中的标签,用于标记元数据;
XML类
三个重要的类:XElement、XAttrubute、XDocument;
可作为XDocument节点的直接子节点:XDeclaration节点、XDocument节点、XElement节点、任何数量的XProcessingInstruction节点;
如果XDocument中有最高级别的XElement节点,则它是XML的根节点;
根元素可以包含任意数量的嵌套XElement、XComment、XProcessingInstruction节点;
创建、保存、加载、显示
static void Main(string[] args)
{
// 创建XML文档
XDocument employeeDoc = new XDocument();
// 创建版本号、字符编码类型、是否外部依赖引用
employeeDoc.Declaration = new XDeclaration("1.0", "utf-8", null);
// 创建根节点
var rootEle = new XElement("Employees");
employeeDoc.Add(rootEle);
// 添加子节点
rootEle.Add(
// 创建第一个元素
new XElement("Employee",
new XElement("Name", "Bob"),
new XElement("PhoneNumber", "408-555-1000")),
// 创建第二个元素
new XElement("Employee",
new XElement("Name", "Sally"),
new XElement("PhoneNumber", "408-555-2000"))
);
//保存XML文档
employeeDoc.Save("employeeDoc.xml");
//加载XML文档
var temp = XDocument.Load("employeeDoc.xml");
Console.WriteLine(temp);
}
/*
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee>
<Name>Bob</Name>
<PhoneNumber>408-555-1000</PhoneNumber>
</Employee>
<Employee>
<Name>Sally</Name>
<PhoneNumber>408-555-2000</PhoneNumber>
</Employee>
</Employees>
*/
查询 XML 的方法
方法名称 | 描述 |
---|---|
Nodes | 返回当前节点的所有类型子节点,可以使用OfType(type)筛选类型<br />var com = xd.Nodes().OfType <XComment>() |
Elements | 返回当前节点的所有或具有某个名字XElement子节点 |
Descendants | 返回所有或具有某个名字的XElement子代节点,不管它处于当前节点下嵌套的层次 |
DescendantsAndSelf | 和Descendants一样,但包含当前节点 |
Ancestors | 返回所有或具有某个名字的上级XElement节点 |
AncestorsAndSelf | 和Ancestors一样,但包含当前节点 |
Parent | 返回当前节点的父节点 |
增加节点以及操作 XML
方法名称 | 描述 |
---|---|
Add | 在当前节点的已有子节点后增加新的子节点 |
AddFirst | 在当前节点的已有子节点前增加新的子节点 |
AddBeforeSelf | 在同级别的当前节点前增加新的节点 |
AddAfterSelf | 在同级别的当前节点后增加新的节点 |
Remove | 删除当前所选的节点和内容 |
RemoveNodes | 删除当前所选的XElement及其内容 |
SetElement | 设置节点内容 |
ReplaceContent | 替换节点内容 |
使用 XML 特性
- 在XElement的构造函数中包含XAttribute构造函数来增加特性;
- 删除特性参照节点操作;
- 增加特性或改变特性使用XElement对象的SetAttributeValue方法;
节点的其他类型
- XComment:XML注释;
- XDeclaration:版本号、字符编码类型、是否外部依赖引用;
- XProcessingInstruction:提供XML文档如何被使用和翻译,关联XML文档和样式表;