返回 C#常用知识小短篇

关于Linq二三事

以下为完整正文内容。

正文

古希腊掌管数据的神 这是没有Linq的时候 var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; var result = new List<int>(); // 找所有偶数,乘10,从大到小排,只要前3个 foreach (int n in numbers) { if (n % 2 == 0) // 过滤 { int transformed = n * 10; // 转换 result.Add(transformed); } } result.Sort(); // 排序 result.Reverse(); // 倒序 var top3 = result.GetRange(0, 3); // 取前3 太麻烦了吧,写起来体验也不连贯,我们需要更优雅的写法。 人们说要优雅,于是Linq出现了 var top3 = numbers .Where(n => n % 2 == 0) // 过滤:只要偶数 .Select(n => n * 10) // 转换:每个乘10 .OrderByDescending(n => n) // 排序:从大到小 .Take(3) // 取前3 .ToList(); // 执行,转成列表 // 结果:80, 60, 40 一气呵成,连贯处理数据,舒服了 那么Linq是怎么来的呢,要想用好一个工具,必须得理解它的原理 Linq本质上就是一个委托链 where就用到了lambda委托,其内部就是一个循环和给定的条件 // Where 的简化本质 public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate) { foreach (var item in source) { if (predicate(item)) // 调用传入的条件 yield return item; } } 大胆联想,LINQ就是一连串的拓展方法,并且所有的参数都是委托 什么是拓展方法:一个类已经写好了,又给它添加了新方法。没有修改源码,也没有用继承 //注意,拓展方法要求必须是静态类 // 给 string 加一个扩展方法 public static class StringExtensions { // this 关键字 + 第一个参数就是要扩展出来的类型(原先没有的) public static string Repeat(this string str, int count) { return string.Concat(Enumerable.Repeat(str, count)); } } // 使用:就像 string 自带的一样 string result = "Hello".Repeat(3); // "HelloHelloHello" //"Hello".Repeat(3)会被编译为: //StringExtensions.Repeat("Hello", 3); 所有参数都是委托: 直接上🌰 // Where 的第二个参数:Func<T, bool> // 意思就是:你给我一个方法,它能判断 T 对不对,返回 true/false Func<int, bool> filter = n => n > 5; // Select 的第二个参数:Func<T, TResult> // 意思就是:你给我一个方法,它能把 T 变成 TResult Func<int, string> transform = n => $"数字:{n}"; var result = numbers .Where(filter) // 每个元素过一遍 filter,true 的留下 .Select(transform); // 每个留下的元素再过一遍 transform,转换 其他常用的也是如此: // FirstOrDefault:只拿第一个,没有就返回默认值 public static T FirstOrDefault<T>(this IEnumerable<T> source,Func<T, bool> predicate) // 判断条件 { foreach (T item in source) if (predicate(item)) // 找到第一个满足条件的 return item; return default(T); // 都没有返回默认值 } // Any:有至少一个没有满足条件的 public static bool Any<T>(this IEnumerable<T> source,Func<T, bool> predicate) // 判断条件 { foreach (T item in source) if (predicate(item)) // 找到一个就立刻 true return true; return false; } // All:是不是全都满足 public static bool All<T>(this IEnumerable<T> source,Func<T, bool> predicate) { foreach (T item in source) if (!predicate(item)) // 找到一个不满足的立刻 false return false; return true; } // Count:满足条件的有几个 public static int Count<T>(this IEnumerable<T> source,Func<T, bool> predicate) { int count = 0; foreach (T item in source) if (predicate(item)) count++; return count; }