经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C# » 查看文章
重学c#系列——linq(1) [二十七]
来源:cnblogs  作者:敖毛毛  时间:2022/12/12 8:58:44  对本文有异议

前言

简单介绍一下linq,linq很多人其实用的很熟练了,但是有些人不知道自己用的是linq。

正文

在介绍linq 之前,先介绍一下集合。

  1. public interface ICollection<T> : IEnumerable<T>, IEnumerable
  2. {
  3. int Count { get; }
  4. bool IsReadOnly { get; }
  5. void Add(T item);
  6. void Clear();
  7. bool Contains(T item);
  8. void CopyTo(T[] array, int arrayIndex);
  9. bool Remove(T item);
  10. }

什么是集合呢?在c# 中拥有上面功能的就是集合。

这里面可以看到集合继承了IEnumerable 这个接口。

继承这个接口意味集合可以列举的,也就是简单来说可以遍历的。

那么c# 中的集合是否一定要继承ICollection。

这个就不一定,比如说字典,字典在现实生活中明显是一组集合吧,那么在c# 中也应该是即可。

为什么字典不继承ICollection,原因也很简单,因为void Add(T item); 对字典来说没有意义。

字典是key 和 value 这种模式,ICollection 是无法满足很多集合需求的,因为集合的多样性太多了(非常丰富)。

那么在c# 中什么样的是集合呢? 继承IEnumerable的就是集合。

如果要数据初始化的话,那么要增加Add方法。

  1. public class TestCollection<T> : IEnumerable<T>
  2. {
  3. public void Add(T a)
  4. {
  5. }
  6. public void Add(List<T> a)
  7. {
  8. }
  9. public IEnumerator<T> GetEnumerator()
  10. {
  11. throw new NotImplementedException();
  12. }
  13. IEnumerator IEnumerable.GetEnumerator()
  14. {
  15. return GetEnumerator();
  16. }
  17. }

这里有两个add,一个增加T,一个增加T列表。

  1. internal class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. List<string> l = new List<string>() { "1", "2", "3"};
  6. TestCollection<string> a = new TestCollection<string>()
  7. {
  8. "123",
  9. l
  10. };
  11. }
  12. }

这样就ok了。

我们知道实现了Ienumerable的可以进行遍历。

因为IEnumerable 返回了一个 IEnumerator GetEnumerator();。

迭代器就是while,然后MoveNext,然后再Current,获取数据。

这里有些人可能会有一个很小的问题,那就是为什么不直接实现迭代器,而是有一个IEnumerable,里面有一个IEnumerator GetEnumerator();。

原因很简单,因为遍历每次都是从头开始,都是一个新的开始。

因为IEnumerator 继承 IDisposable, 如果需要每次遍历完做某些事情的话,可以放在IEnumerator的void Dispose();中实现。

所以foreach 实际上是干了这样一件事。

那么foreach 是否一定要继承IEnumerable 呢? 这个不一定。

foreach 采用一个duck typing的这种方式,duck typing是什么意思呢?就是走起来想一只鸭子,然后叫起来像一只鸭子,那么就是鸭子。

只要有GetEnumerator就行:

  1. internal class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. List<string> l = new List<string>() { "1", "2", "3"};
  6. TestForeach<string> a = new TestForeach<string>();
  7. foreach (var b in a)
  8. {
  9. }
  10. }
  11. }
  12. public class TestForeach<T>
  13. {
  14. public IEnumerator<T> GetEnumerator()
  15. {
  16. throw new NotImplementedException();
  17. }
  18. }

在foreach 循环中不能进行赋值。

同样在foreach 循环中不能对集合的个数进行修改。

无论是增加还是删除list的version都会发生变化。

很多书里面介绍了,为什么不能复制和增加集合个数,这样会使人头脑不清醒。

因为这是遍历,应该是一个原子,这样的设计不会添加歧义性,单一职责逻辑清晰能减少不必要的bug。

一般来说都会继承一下IEnumerable 这个接口。 为什么呢?因为linq。

linq 是 language integated query,语言集成查询。

也就是说定义了一套规范哈,对于我们来说其实不用太在意这个规范是什么,大体看一下就行。

对IEnumerable而言,实现的就在system.IEnumberable.linq 上面,引用用就好。

然后linq有一个很大的特点,就是延迟执行。

然后来说下这个延迟执行是怎么实现的哈。

比如我们的list 经过where 之后,其实在运行时就不是linq。

运行时是这个类型WhereListIterator。

就看个list的。

执行where 其实就是把list 给 WhereListIterator。

并没有生成新的list,所以说不会执行where操作。

当遍历的时候就会执行WhereListIterator的movenext。

遍历的时候就会做条件判断。

所以呢,如果进行多次遍历后呢,其实一直都在执行你的where 语句。

如果需要遍历多次,where 循环后,最好直接tolist转换成一个list。

当然有兴趣可以去看下其他的,这里只是举个例子,其实就是用包装器模式实现的。

这样经过层层包装,人们就会想啊,如果where 语句按照顺序执行,那么不会很慢啊。

所以linq还可以并行实现,使用asParallel(),这个东西来实现。

这样运行就是并行的, 先不管实现,并行篇会介绍,只需要知道官方帮我们实现了,这样运行更快就可以了。

因为东西比较多,下一节是一些复杂的linq和匿名linq,下下节是查询表达式。 linq 是实现其实很复杂,但是用起来是真的简单。

原文链接:https://www.cnblogs.com/aoximin/p/16973618.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号