LINQ简介
/*
* 查询是一种从数据源检索数据的表达式。 查询通常用专门的查询语言来表示。 随着时间的推移,
* 人们已经为各种数据源开发了不同的语言;例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。
* 因此,开发人员对于他们必须支持的每种数据源或数据格式,都不得不学习一种新的查询语言。
* LINQ 通过提供处理各种数据源和数据格式的数据的一致模型,简化了这一情况。 在 LINQ 查询中,
* 始终会用到对象。 可以使用相同的基本编码模式来查询和转换 XML 文档、SQL 数据库、ADO.NET 数据集、
* .NET 集合中的数据以及 LINQ 提供程序可用的任何其他格式的数据。
*
* Linq to object (数组、list集合)--内存里面的数据
* Linq to sql (查询数据用的)--在数据库数据
* Linq to Xml 查询XML文件
*
* 所有 LINQ 查询操作都由以下三个不同的操作组成:
* 1.获取数据源。
* 2.创建查询。
* 3.执行查询
*
* 1.LINQ查询表达式
*
* from i in list
* where i < 10
* orderby i
* select i;
*子句中from,where,orderby selece关键字都是linq预定义的关键字
*所有的Linq查询表达式都必须以from子句开始,以select或者group 子句结束
*在开头和结束子句之间,可以使用where,orderby join等其他from子句
*
*Linq查询表达式开头的from子句用于指定数据源 格式:
*from [单个数据源元素] in [数据源]
*
*linq查询表达式结束的select子句用于指定返回的目标数据。格式:
*select[目标元素]
*
*
*
*
*/
class Program
{
static void Main(string[] args)
{
#region linq查询表达式
//练习1 数组
//Array
//获取数组数据源
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
//创建查询
IEnumerable<int> numQuery =
from num in numbers
where (num % 2) == 0
select num; //用于指定返回的目标数据
//执行查询
foreach (int num in numQuery)
{
Console.WriteLine("{0}", num);
}
Console.WriteLine("---------------------------");
//list数据源 List<int>数据类型,实现了IEnumerable<T>接口,所以可以使用Linq
List<int> list = new List<int> { 1, 2, 4, 3, 9, 5, 43, 21 };
var _list = from i in list
where i < 10
orderby i
select i;
foreach (var item in _list)
{
Console.WriteLine( item);
}
#endregion
Console.ReadKey();
}
}
编写一个扩展方法
/*
* 扩展方法
* 静态类里的静态方法,参数列表最前面加个this+要扩展到的类型
* 使用场景:在不修改源码的情况下为其他类型修改方法
*
*/
class Program
{
static void Main(string[] args)
{
Cal cal = new Cal();
Console.WriteLine(cal.AddNew(1, 2, 4));
Console.ReadKey();
}
}
public class Cal
{
public int Add(int a, int b)
{
return a + b;
}
//public int Add(int a, int b, int c)
//{
// return a + b + c;
//}
}
static class CalExtend
{
public static int AddNew(this Cal cal,int a,int b,int c)
{
return a + b + c;
}
}
LINQ查询方法
/*
* public static IEnumerable<TSource> Where<TSource>
* (this IEnumerable<TSource> source, Func<TSource, bool> predicate);
*
* Func<TSource, bool>:是一个委托,此委托返回类型是bool,传入的参数数据类型为数据源中元素的数据类型
* Where(i => i < 10):这是lambda表达式,传入的参数为TSource类型的参数为i ,如果i满足小于10返回true,则保留元素
* 返回false,即将元素过滤
*
* 扩展方法
* 静态类里的静态方法,参数列表最前面加个this+要扩展到的类型
* 使用场景:在不修改源码的情况下为其他类型修改方法
*
*/
class Program
{
static void Main(string[] args)
{
//数据源
List<int> list = new List<int> { 1, 2, 4, 3, 9, 5, 43, 21 };
var _list = list.Where(i => i < 10).OrderBy(i => i);
foreach (var item in _list)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
LINQ查询的延迟加载
/*
* 虽然我们往list里面添加了两个新的元素,但是没有对_list进行操作
* 如果LINQ查询是将结果查询到后,存储在_list指向的内存中,那么两次遍历结果应该一样
* 但两个遍历结果却不同 这是为什么?
* 我们可以将LINQ查询仅仅理解成一个表达式,编译的时候它被存于程序集中,程序运行时,它并没有被拿去执行对数据源的查询
* 而是当我们去遍历或者读取数据结果时,这个表达式才会被执行去查询数据源,这也就是所谓的查询延迟加载
*
* 只有当foreach的时候,才会逐个返回结果中的元素
* 因为类似Where的Linq操作,不是在内存里重新开辟内存存放结果,而是只保存了查询的命令,
* 这样我们可以在后面继续增加新的命令形成一系列的组合操作,不至于每次查询都浪费资源生成新的中间结果。
*
* 当我们对查询结果进一步调用ToArray()、ToList()方法后,返回的数组或者集合会丧失延迟加载的特征
* 因为这个两个操作会在内存在开辟空间,并需要将查询结果存入内存中
* ToList()之后,LINQ查询被执行了,查询到的结果被存储在了内存中,成为了新的数据源
*
* 然而,也有少数的Linq命令是即时加载的,比如Count、First、Last等方法。因为这些方法本身就涉及到了遍历各个元素,
* 既然内部需要foreach遍历,自然就不是延迟加载了。
*
*/
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int> { 1, 2, 4, 3, 9, 5, 43, 21 };
var _list = list.Where(i => i < 10).OrderBy(i => i);
//var _list = list.Where(i => i < 10).OrderBy(i => i).ToList();
Console.WriteLine("第一次遍历_list");
foreach (var item in _list)
{
Console.WriteLine(item);
}
Console.WriteLine("-----------------------------");
list.Add(8);
list.Add(6);
Console.WriteLine("第二次遍历_list");
foreach (var item in _list)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
Linq标准查询操作符
class Program
{
static void Main(string[] args)
{
Person p1 = new Person("贾宝玉", 16);
Person p2 = new Person("林黛玉", 15);
Person p3 = new Person("薛宝钗", 15);
Person p4 = new Person("王熙凤", 22);
List<Person> list = new List<Person>() { p1, p2, p3, p4 };
List<string> listName = list.Where(p => p.Age > 15) //过滤掉年龄不超过15岁的人
.OrderByDescending(p => p.Age)//按照年龄的降序排列
.Select(p => p.Name)//将查询结果投射成名字
.ToList(); //将结果转成集合
Console.WriteLine($"年龄超过15岁的共有{listName.Count()}人,按年龄由大到小进行排序结果如下:");
//遍历集合
foreach (var name in listName)
{
Console.WriteLine(name);
}
Console.WriteLine("--------------------------------");
Console.WriteLine($"所有4个人的平均年龄是{list.Average(p=>p.Age)}岁");
Console.WriteLine($"所有4个人的总年龄是{list.Sum(p => p.Age)}岁");
Console.WriteLine($"所有4个人的年龄最大的{list.Max(p => p.Age)}岁");
Console.WriteLine("-----------------------------------------");
//获取唯一一个年龄大于16岁的人,如果多个会抛出异常
Person pUpper16 = list.Single(p => p.Age > 16);
Console.WriteLine($"唯一一个年龄大于16岁的是{pUpper16.Age}岁的{pUpper16.Name}");
Console.ReadKey();
}
}
public class Person
{
public Person(string name,int age)
{
Name = name;
Age = age;
}
public string Name { get; set; }
public int Age { get; set; }
}
LinqToXML
?xml version="1.0" encoding="utf-8" ?>
<!-- xml 可扩展的标记语言 解决HTML不可扩展的问题,作用:保存或传输数据,不是用来显示数据的。-->
<Hopu>
<Specialty SpecialtyName="1">
<Class>物联网1班</Class>
<Class>物联网2班</Class>
</Specialty>
<Specialty SpecialtyName="2">
<Class>云计算1班</Class>
<Class>云计算2班</Class>
</Specialty>
<Specialty SpecialtyName="3">
<Class>电商1班</Class>
<Class>电商2班</Class>
<Class>电商3班</Class>
<Class>电商4班</Class>
</Specialty>
</Hopu>
/*
* 我们对XML文件使用LINQ查询操作符,它使用的语法和我们之前对泛型集合进行的LINQ查询使用了where(),select()方法
* 语法风格一致
* 但Attribute()和Descendants()方法,时XML的LINQ查询特有的,它们位于System.Xml.Linq命名空间下,需要引入
*
*
*
*/
class Program
{
static void Main(string[] args)
{
//加载xml文件,引入命名空间
XElement root = XElement.Load(@"myxml.xml");
//使用LINQ查询表达式
//[speʃəlti]
var specialties = from specialty in root.Elements("Specialty")
where specialty.Attribute("SpecialtyName").Value == "1"
select specialty;
foreach (var item in specialties)
{
Console.WriteLine(item);
}
Console.WriteLine("-------------------");
//使用LINQ查询方法Descentdants() [dɪˈsent] 获取所有子代元素
var classes = specialties.Where(s => s.Attribute("SpecialtyName").Value == "1").Descendants();
foreach (var item in classes)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
网友评论