linq可以对多种数据源和对象进行查询,如数据库、数据集、XML文档、数组等。
通过对linq的使用,可以减少代码量并优化检索操作。
LINQ关键字
from 指定数据源和范围变量
where 根据布尔表达式(由逻辑与 或 等组成)从数据源中筛选元素
select 指定查询结果中的元素所具有的类型或表现形式
group 对对查询结果按照键值进行分组
into 提供一个标示符,它可以充当对 join group 或 select 子句结果的引用
orderby 对查询出的元素进行排序
join 按照两个指定匹配条件来联接俩个数据源
let 产生一个用于查询表达式中子表达式查询结果的范围变量
1. 组成
// 1,获取数据源 List<int> numbers = new List<int>() { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; // 2,创建查询 var numQuery = from num in numbers where num % 2 == 0 select num; // 3,执行查询 foreach (var num in numQuery) { Console.WriteLine("{0,1}", num); }
static void Main(string[] args) { //获取数据源 string[] names = { "Alen", "Zhen", "Chen","Song", "Hel", "Ken", "Aln", "Zen", "Cen", "He", "Ke", }; //创建查询 var queryResults = from n in names where n.StartsWith("S") select n; Console.WriteLine("Names beginning with S:"); //执行查询 foreach (var item in queryResults) { Console.WriteLine(item); } Console.Write("Program finished,press Enter/Reurn to continue:"); Console.ReadLine(); }
2. 语句使用
//1.用var关键字声明结果变量 //2.指定数据源:from 子句 //3.指定条件:where 子句 //4.指定元素:select子句 //5.完成:使用foreach循环 string[] names = { "Alono", "Zheng", "Yuan", "Song", "Simle", "Hsieh", "Small", "She", "Sza", "Sam", "Fa", "Iyl" }; var queryResults = from n in names where n.StartsWith("S") orderby n descending//按照最后一个字母排序 ordeby n.Substring(n.Length - 1) select n;//查询语法 var queryResults1 = names.OrderBy(n => n).Where(n => n.StartsWith("S"));//方法语法 Lambda 表达式 // var queryResults = names.OrderByDescending(n => n).Where(n => n.StartsWith("S")); foreach (var item in queryResults) Console.WriteLine(item); Console.ReadKey();
2.1 from语句
创建一个LINQ表达式必须要以from子句开头
单个from语句
//获取数据 string[] a = { "日本","德国","英国","美国","澳大利亚"}; //创建查询,创建一个LINQ表达式必须要以from子句开头 var myQuery = from n in a where n.IndexOf("国") > 0 select n; //执行查询 foreach(var item in myQuery) { Console.WriteLine(item); } Console.ReadKey();
复合from子句
如果一个集合中的某个对象依旧是一个集合,就可以使用from
子句进行筛选。
public class CustomerInfo1 { public string Name { get; set; } public int Age { get; set; } public List<string> TelTable { get; set; } } class Test03_MultiFrom { static void Main(string[] args) { //获取数据源 List<CustomerInfo1> customer = new List<CustomerInfo1> { new CustomerInfo1{Name = "郭啸天",Age = 100,TelTable = new List<string>{"123321","321123"}}, new CustomerInfo1{Name = "郭靖",Age = 80,TelTable = new List<string>{"456654","654456"}}, new CustomerInfo1{Name = "郭芙", Age = 60,TelTable = new List<string>{"789987","987789"}} }; //创建查询 var query = from CustomerInfo1 ci in customer from tel in ci.TelTable where tel.IndexOf("789987") > -1 select ci;
var query1=customer.SelectMany(c => c.TelTable, (c,r) => new { CustomerInfo1 = c, Tel = r }).Where(u=>u.Tel.IndexOf("789987")>-1); //执行查询 foreach (var item in query) { Console.WriteLine("姓名:{0} 年龄:{1}", item.Name, item.Age); foreach (var tel in item.TelTable) { Console.WriteLine("电话:{0}", tel); } } Console.ReadKey(); } }
2.2 where 语句
where子句的作用就是筛选元素,除了开始和结束位置, where子句几乎可以出现在LINQ表达式的任意位置。一个LINQ表达式中可以有where子句,也可以没有;可以有一个,可以有多个;多个where子句之间的关系相当于逻辑“与”,每个where子句可以包含1个或多个逻辑表达式,这些条件成为“谓词”,多个谓词之间用布尔运算符隔开,比如逻辑“与”用&&,逻辑“或”用||,而不是用SQL中的AND或OR。
//查询语句
var racrers = from r in Formulal.GetChampions() where r.Wins > 15 && (r.Country == "China" || r.Country == "UK") select r;
//扩展方法
var racres2 = Formulal.GetChampions() .Where(r => r.Wins > 15 && (r.Country == "China" || r.Country == "UK")) .Select(r => r);
这两种执行的结果都是一样的。但是并不是所有的LINQ查询都可以使用LINQ查询表达式完成,也不是所有的LINQ扩展方法都能够映射到LINQ查询表达式语句上。LINQ扩展方法使用的范围要比查询表达式更广泛,尤其是一些高级查询,只能或更多的是使用扩展方法完成。同时,这两种形式也可以组合使用。
//使用索引筛选,只能使用扩展方法,不能使用Linq查询语句 var racers3 = Formulal.GetChampions() .Where((r, index) => r.LastName.StartsWith("A") && index % 2 != 0);
2.3 排序子句
OrderBy/OrderByDescending/ThenBy/ThenByDescending
OrderBy()
:按升序对序列的元素进行排序。
ThenBy()
:按升序对序列中的元素进行后续排序。
OrderByDescending()
:按降序对序列的元素进行排序。
ThenByDescending()
:按降序对序列中的元素进行后续排序。
//查询语句 var racers3 = (from r in Formulal.GetChampions() orderby r.Country, r.LastName, r.FirstName ascending select r).Take(10);
//扩展方法 var racers4 = Formulal.GetChampions() .OrderBy(r => r.Country) .ThenBy(r => r.LastName) .ThenByDescending(r => r.FirstName) .Take(10);
2.4 分组
GroupBy
如果要根据一个关键字值 对查询结果分组,可以使用group
子句。对应的扩展方法为GroupBy()
。
//查询语句 var countries = from r in Formulal.GetChampions() group r by r.Country into g //将分组信息放入标识符g中 orderby g.Count() descending, g.Key where g.Count() >= 2 select new { Country = g.Key, Count = g.Count() }
//扩展方法 var countries2 = Formulal.GetChampions() .GroupBy(r => r.Country) .OrderByDescending(g => g.Count()) .ThenBy(g => g.Key) .Where(g => g.Count() >= 2) .Select(g => new { Country = g.Key, Count = g.Count() });
2.5 Let子句 及 匿名类属性
上述的分组查询语句,中间多次调用了Count
方法,使用let
子句可以改变这种方式。let
允许在LINQ查询中定义变量。
var countries = from r in Formulal.GetChampions() group r by r.Country into g let count = g.Count() orderby count descending, g.Key where count >= 2 select new { Country = g.Key, Count = count };
使用方法语法时,为了避免Count
方法被调用多次,可以使用Select
方法创建一个匿名类型,将Count
方法的结果作为匿名类的属性进行传递
var countries2 = Formulal.GetChampions() .GroupBy(r => r.Country) .Select(g => new { Group = g, Count = g.Count() }) .OrderByDescending(g => g.Count) .ThenBy(g => g.Group.Key) .Where(g => g.Count >= 2) .Select(g => new { Country = g.Group.Key, Count = g.Count });
注意:应考虑根据let
子句或Select
方法创建的临时对象的数量 。查询大列表时,创建的大量对象需要以后进行垃圾收集 ,这可能对性能产生巨大影响。
2.6 join子句
如果一个数据源中元素的某个属性可以跟另一个数据源中元素的属性进行相等比较,那么这两个数据源可以用join子句进行关联。jion子句用equals关键字进行比较,而不是常见的==。var racersAndTeams = (from r in racers join t in teams on r.Year equals t.Year orderby t.Year select new { r.Year, Champion = r.Name, Constructor = t.Name }).Take(10);
左外连接
var racersAndTeams = (from r in racers join t in teams on r.Year equals t.Year into rt from t in rt.DefaultIfEmpty() orderby r.Year select new { r.Year, Champion = r.Name, Constructor = t == null ? "no constructor" : t.Name }).Take(10);
2.7 集合操作
Intersect()
:通过使用的默认相等比较器对值进行比较,生成两个序列的交集。
Distinct()
:返回序列中通过使用指定的非重复元素。
Union()
:通过使用默认的相等比较器生成的两个序列的并集。
Except()
:通过使用默认的相等比较器对值进行比较,生成两个序列的差集。
List<Order> orders = new List<Order>{ new Order {ID="A",Amount=100}, new Order {ID ="B",Amount =200}, new Order {ID ="H",Amount =300}}; var customersIDs = from c in customers select c.ID; var ordersIDs = from o in orders select o.ID; var customersWithOrders = customersIDs.Intersect(ordersIDs);//Intersect() foreach (var item in customersWithOrders ) Console.WriteLine(item ); Console.WriteLine("-------------------------"); var ordersNoCustomers = ordersIDs.Except(customersIDs);//Except() foreach (var item in ordersNoCustomers ) Console.WriteLine(item ); Console.WriteLine("-------------------------"); var allCustomersOrders = ordersIDs.Union(customersIDs);//Union() foreach (var item in allCustomersOrders) Console.WriteLine(item); //Console.ReadKey();
2.8 分区
Take和TakeWhile,Skip和SkipWhile
Take():从序列的开头返回指定的数量的连续元素。
TakeWhile():只要指定的条件为true,就返回序列中的元素,然后跳过其余元素。
Skip():跳过指定的数量的序列中的元素,然后返回剩余元素。
SkipWhile():只要指定的条件为真,就会跳过序列中的元素,然后返回剩余的元素。
int pageSize = 5; int numberPages = (int)Math.Ceiling(Formulal.GetChampions().Count() / (double)pageSize); for (int page = 0; page < numberPages; page++) { Console.WriteLine("Page "+page); var racers = (from r in Formulal.GetChampions() orderby r.LastName, r.FirstName select r.FirstName + " " + r.LastName) .Skip(page * pageSize).Take(pageSize); foreach(var name in racers) { Console.WriteLine(name); } Console.WriteLine( ); }
2.9 聚合操作符
聚合操作符(如Count、Sum、Min、Max、Average和Aggregate操作符)不返回一个序列,而返回一个值。
Count():返回序列中的元素数。
Sum():计算一系列数值的总和。
Min():返回值序列中的最小值。
Max():返回值序列中的最大值。
Average():计算一系列数值的平均值。
Aggregate(): 对一个序列应用累加器函数。
Console.WriteLine("Count():"); var query = from r in Formulal.GetChampions() let numberYears = r.Years.Count() where numberYears >= 3 orderby numberYears descending, r.LastName select new { Name = r.FirstName + " " + r.LastName, TimesChampion = numberYears }; foreach(var r in query) { Console.WriteLine(r.Name+" "+r.TimesChampion); } Console.WriteLine(); Console.WriteLine("Sum():"); var countries = (from c in from r in Formulal.GetChampions() group r by r.Country into c select new { Country = c.Key, Wins = (from r1 in c select r1.Wins).Sum() } orderby c.Wins descending, c.Country select c).Take(5); foreach(var country in countries) { Console.WriteLine(country.Country+" "+country.Wins); }
==============================================相关知识点扩展==================================================
相关知识点扩展
1 var 、 dynamic 及匿名类型
var model = new //3.0 { Id = 2, Name = "undefined", Age = 25, ClassId = 2, }
Console.WriteLine(model.Id); //编译错误
Console.WriteLine(model, Name); //编译错误
dynamic model = new //4.0 dynamic避开编译器检查 { Id = 2, Name = "undefined", Age = 25, ClassId = 2, }
Console.WriteLine(model.Id); //编译不会报错
Console.WriteLine(model, Name); //编译不会报错
2. 扩展方法
数据准备
/// <summary> /// 学生实体 /// </summary> public class Student { public int Id { get; set; } public int ClassId { get; set; } public string Name { get; set; } public int Age { get; set; } public void Study() { Console.WriteLine("{0} {1}跟着Eleven老师学习.net高级开发", this.Id, this.Name); } public void StudyHard() { Console.WriteLine("{0} {1}跟着Eleven老师努力学习.net高级开发", this.Id, this.Name); } ////学习实战班 //public void StudyPractise() //{ // Console.WriteLine("{0} {1}跟着Mark老师学习.net实战开发", this.Id, this.Name); //} }
/// <summary> /// 扩展方法:静态类里面的静态方法,第一个参数类型前面加上this /// </summary> public static class ExtendMethod { public static void StudyPractise(this Student student) { Console.WriteLine("{0} {1}跟着Mark老师学习.net实战开发", student.Id, student.Name); } }
方法调用
//扩展方法调用,很像实例方法,就像扩展了Student的逻辑
//1 第三方的类,不适合修改源码,可以通过扩展方法增加逻辑
//优先调用实例方法,最怕扩展方法增加了,别人类又修改了
//2 适合组件式开发的扩展(.NetCore),定义接口或者类,是按照最小需求,但是在开发的时候又经常需要一些方法,就通过扩展方法 context.Response.WriteAsync 中间件的注册
//3 扩展一些常见操作
//会污染基础类型,一般少为object 没有约束的泛型去扩展
student.Study(); ExtendMethod.StudyPractise(student); student.StudyPractise();
3. yield 迭代器
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MyLinq { /// <summary> /// http://www.cnblogs.com/YamatAmain/p/5016464.html /// /// 含有yield的函数说明它是一个生成器,而不是普通的函数。当程序运行到yield这一行时,该函数会返回值,并保存当前域的所有变量状态; /// 等到该函数下一次被调用时,会从上一次中断的地方开始执行,一直遇到下一个yield, 程序返回值, 并在此保存当前状态; 如此反复,直到函数正常执行完成。 /// /// 迭代器模式是设计模式中行为模式(behavioral pattern)的一个例子,他是一种简化对象间通讯的模式,也是一种非常容易理解和使用的模式。 /// 简单来说,迭代器模式使得你能够获取到序列中的所有元素 而不用关心是其类型是array,list,linked list或者是其他什么序列结构。 /// 这一点使得能够非常高效的构建数据处理通道(data pipeline)--即数据能够进入处理通道,进行一系列的变换,或者过滤,然后得到结果。事实上,这正是LINQ的核心模式。 /// 在.NET中,迭代器模式被IEnumerator和IEnumerable及其对应的泛型接口所封装。如果一个类实现了IEnumerable接 口,那么就能够被迭代; /// 调用GetEnumerator方法将返回IEnumerator接口的实现,它就是迭代器本身。迭代器类似数据库中的游标,他是 数据序列中的一个位置记录。 /// 迭代器只能向前移动,同一数据序列中可以有多个迭代器同时对数据进行操作。 /// </summary> public class YieldShow { /// <summary> /// /// </summary> public void Show() { IEnumerable<int> iterable = this.CreateEnumerable();//1 不会直接执行 //IEnumerator iterator = iterable.GetEnumerator(); IEnumerator<int> iterator = iterable.GetEnumerator(); Console.WriteLine("开始迭代"); while (true) { Console.WriteLine("调用MoveNext方法……"); Boolean result = iterator.MoveNext();//2 正式开启CreateEnumerable Console.WriteLine("MoveNext方法返回的{0}", result); if (!result) { break; } Console.WriteLine("获取当前值……"); Console.WriteLine("获取到的当前值为{0}", iterator.Current); } Console.ReadKey(); } /// <summary> /// 普通获取数据 /// </summary> /// <returns></returns> public IEnumerable<int> CommonMethod() { List<int> results = new List<int>(); int counter = 0; int result = 1; while (counter++ < 10) { Thread.Sleep(1000); Console.WriteLine($"获取{counter}次数据"); result = result * 2; results.Add(result); } return results; } /// <summary> /// yield获取数据 /// </summary> /// <returns></returns> public IEnumerable<int> YieldMethod() { int counter = 0; int result = 1; while (counter++ < 10) { Thread.Sleep(1000); Console.WriteLine($"获取{counter}次数据"); result = result * 2; yield return result; } } public IEnumerable<int> CreateEnumerable() { try { Console.WriteLine("{0} CreateEnumerable()方法开始", DateTime.Now); for (int i = 0; i < 5; i++) { Console.WriteLine("{0}开始 yield {1}", DateTime.Now, i); yield return i; Console.WriteLine("{0}yield 结束", DateTime.Now); if (i == 4) { yield break;//直接终结迭代 4会出现的,, } } Console.WriteLine("{0} Yielding最后一个值", DateTime.Now); yield return -1; Console.WriteLine("{0} CreateEnumerable()方法结束", DateTime.Now); } finally { Console.WriteLine("停止迭代!"); } } } }
转自https://www.cnblogs.com/for-easy-fast/articles/12340925.html
标签:Count,Console,C#,Linq,WriteLine,var,new,select From: https://www.cnblogs.com/castlewu/p/16987081.html