深入理解迭代器与集合 Part1【Linq学习系列】
2010-06-25 23:26
399 查看
Linq学习系列
第一节 深入理解迭代器与集合
本节分五部分:
第一部分,迭代器的原理与实现;
第二部分,迭代器的高级用法
[b] 第三部分,使用迭代器常见的错误[/b]
第四部分,Linq中用到的迭代器
第五部分,扩展Linq(Linq To Reflection)
Part1 解析迭代器的各种特性
1.0 前言
不管是Linq To Objects,Linq To Sql,还是Linq To Xml等等,Linq都是用于对集合的操作。而迭代器是Linq的基础之一。
迭代器是一种模式,用于顺序访问一个聚合对象中的各个元素。更具体的说,在.Net中,是通过实现IEnumerable,IEnumerable<T>来实现的。
迭代器模式参看:http://blog.sina.com.cn/s/blog_45d7d4010100bz50.html。
也许有人觉得集合不就是数组吗,比如Int[] myIntegers=Int[100];直接指定下标myIntergers[x]不就可以访问任意元素了吗?为什么要这么麻烦?
集合有很多种,链表,树(比如xml),图都是集合,而且集合中的元素也不一定就是同样的类型。有些集合无法使用任意指定的方式来遍历。最特殊的例子(也许不是很恰当),互联网就是一个集合。google的网络爬虫就是一个迭代器,它遍历整个互联网,抓取的东西包括网页,图片,视频,音频等等。
我们都熟悉SQL语句,稍微深入一点就知道,当我们的查询条件中不包含索引时,其实数据库系统在后台要执行所谓的“全表扫描”,而迭代器就是执行“全集合扫描”的对象。(Linq操作的对象是不是也可以建立一个索引呢?可以思考一下。)
重要概念:
集合:对于Linq来说,它可操作的对象是实现了IEnumerable<T> 的类。因此,对于Linq来说,集合是指相同类型的集合。不管它们是以何种形式组合在一起,必须都是返回T类型。而且,这种集合都包含了迭代器。但是,请注意,集合所包含的类型跟迭代器返回的类型并不需要相同,并且这个特性在C#2.0就可以实现。比如,一个字符串的集合,可以实现一个返回每个字符串长度的迭代器(请看1.5节)。
迭代器:实现了IEnumerator<T>和IEnumerator接口的类都是迭代器。.NET Fraemwork实现了许多迭代器:CharEnumerator,SZGenericArrayEnumerator<T> 等等。我们可以实现这两个接口定制自己的迭代器。你可以直接使用迭代器的方法来遍历,也可以使用foreach语句,但是这并不是本质区别。
从上面的描述也可以看出,Linq所能操作的集合要比SQL丰富,SQL只能操作关系表;其次,它提供了对强类型集合的操作,减少了错误的发生。既然提供了这么多丰富的功能,肯定有无数背后的故事。
但是,我们先从最简单的数组开始。
1.1 数组
在没有迭代器的时代,如果我们要遍历一个数组,我们一般用这样的写法:
Int myIntegers=Int[100];
for(i=0;i<myIntegers.Length;i++)
{
Console.WriteLine(myIntegers[i]);
}
对于这种方式,我们经常碰到的问题就是:越界。编译器无法判断,因此这种错误只能在运行时查出来。我们看看迭代器遍历的方式:
foreach(int i in myIntegers)
{
Console.WriteLine(i);
}
其实对于上述写法,编译器完全可以使用语法糖的技巧,偷偷的编译成如下语句:
int current=0;
while(myIntegers.Lenght> current)
{
int i= myIntegers[current];
Console.WriteLine(i);
current++;
}
这样也可以解决越界的问题。但是实际上并没有使用上述方法,而是使用迭代器实现的。在C#(2.0以后)中,每一个数组对象都实现了IEnumerable<T>接口。(还实现了ICollection<T>,IList<T>接口)。定义如下:
public interface IEnumerable<T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
以Int型数组为例,当我们声明一个Int型数组Int[]myIntegers时,系统会自动生成一个类:System.Int[],名称空间跟Int类型是一样的。示例代码:
代码 public class MyTreeView : TreeView
{
IEnumerator<TreeNode> GetDepthFirstEnumerator()
{
return new DepthFirstEnumerator(this);
}
IEnumerator<TreeNode> GetWidthFirstEnumerator()
{
return new WidthFirstEnumerator(this);
}
}
')InsertToEditor('MyTreeView tree=new MyTreeView ();
foreach(TreeNode node in tree)
{
// do someting...
}
')
第一节 深入理解迭代器与集合
本节分五部分:
第一部分,迭代器的原理与实现;
第二部分,迭代器的高级用法
[b] 第三部分,使用迭代器常见的错误[/b]
第四部分,Linq中用到的迭代器
第五部分,扩展Linq(Linq To Reflection)
Part1 解析迭代器的各种特性
1.0 前言
不管是Linq To Objects,Linq To Sql,还是Linq To Xml等等,Linq都是用于对集合的操作。而迭代器是Linq的基础之一。
迭代器是一种模式,用于顺序访问一个聚合对象中的各个元素。更具体的说,在.Net中,是通过实现IEnumerable,IEnumerable<T>来实现的。
迭代器模式参看:http://blog.sina.com.cn/s/blog_45d7d4010100bz50.html。
也许有人觉得集合不就是数组吗,比如Int[] myIntegers=Int[100];直接指定下标myIntergers[x]不就可以访问任意元素了吗?为什么要这么麻烦?
集合有很多种,链表,树(比如xml),图都是集合,而且集合中的元素也不一定就是同样的类型。有些集合无法使用任意指定的方式来遍历。最特殊的例子(也许不是很恰当),互联网就是一个集合。google的网络爬虫就是一个迭代器,它遍历整个互联网,抓取的东西包括网页,图片,视频,音频等等。
我们都熟悉SQL语句,稍微深入一点就知道,当我们的查询条件中不包含索引时,其实数据库系统在后台要执行所谓的“全表扫描”,而迭代器就是执行“全集合扫描”的对象。(Linq操作的对象是不是也可以建立一个索引呢?可以思考一下。)
重要概念:
集合:对于Linq来说,它可操作的对象是实现了IEnumerable<T> 的类。因此,对于Linq来说,集合是指相同类型的集合。不管它们是以何种形式组合在一起,必须都是返回T类型。而且,这种集合都包含了迭代器。但是,请注意,集合所包含的类型跟迭代器返回的类型并不需要相同,并且这个特性在C#2.0就可以实现。比如,一个字符串的集合,可以实现一个返回每个字符串长度的迭代器(请看1.5节)。
迭代器:实现了IEnumerator<T>和IEnumerator接口的类都是迭代器。.NET Fraemwork实现了许多迭代器:CharEnumerator,SZGenericArrayEnumerator<T> 等等。我们可以实现这两个接口定制自己的迭代器。你可以直接使用迭代器的方法来遍历,也可以使用foreach语句,但是这并不是本质区别。
从上面的描述也可以看出,Linq所能操作的集合要比SQL丰富,SQL只能操作关系表;其次,它提供了对强类型集合的操作,减少了错误的发生。既然提供了这么多丰富的功能,肯定有无数背后的故事。
但是,我们先从最简单的数组开始。
1.1 数组
在没有迭代器的时代,如果我们要遍历一个数组,我们一般用这样的写法:
Int myIntegers=Int[100];
for(i=0;i<myIntegers.Length;i++)
{
Console.WriteLine(myIntegers[i]);
}
对于这种方式,我们经常碰到的问题就是:越界。编译器无法判断,因此这种错误只能在运行时查出来。我们看看迭代器遍历的方式:
foreach(int i in myIntegers)
{
Console.WriteLine(i);
}
其实对于上述写法,编译器完全可以使用语法糖的技巧,偷偷的编译成如下语句:
int current=0;
while(myIntegers.Lenght> current)
{
int i= myIntegers[current];
Console.WriteLine(i);
current++;
}
这样也可以解决越界的问题。但是实际上并没有使用上述方法,而是使用迭代器实现的。在C#(2.0以后)中,每一个数组对象都实现了IEnumerable<T>接口。(还实现了ICollection<T>,IList<T>接口)。定义如下:
public interface IEnumerable<T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
以Int型数组为例,当我们声明一个Int型数组Int[]myIntegers时,系统会自动生成一个类:System.Int[],名称空间跟Int类型是一样的。示例代码:
代码 public class MyTreeView : TreeView
{
IEnumerator<TreeNode> GetDepthFirstEnumerator()
{
return new DepthFirstEnumerator(this);
}
IEnumerator<TreeNode> GetWidthFirstEnumerator()
{
return new WidthFirstEnumerator(this);
}
}
')InsertToEditor('MyTreeView tree=new MyTreeView ();
foreach(TreeNode node in tree)
{
// do someting...
}
')
相关文章推荐
- 深入Java集合学习系列:HashMap的实现原理
- HTTP协议学习系列--深入理解HTTP协议
- 深入Java集合学习系列:HashMap的实现原理
- git干货系列:(二)深入学习之前先理解git暂存区
- 深入Java集合学习系列:LinkedHashSet的实现原理
- 深入Java集合学习系列:ArrayList的实现原理
- 分布式缓存技术redis学习系列----深入理解Spring Redis的使用
- 深入Java集合学习系列:HashMap的实现原理
- 深入Java集合学习系列:HashMap的实现原理
- 深入Java集合学习系列:HashSet的实现原理
- 深入Java集合学习系列:HashMap的实现原理
- 深入Java集合学习系列:HashMap的实现原理
- 深入Java集合学习系列:LinkedHashMap的实现原理
- 深入Java集合学习系列:LinkedHashSet的实现原理
- 深入Java集合学习系列:ConcurrentLinkedQueue及其实现原理
- 深入Java集合学习系列:HashMap的实现原理
- 【深入理解java集合系列】HashSet实现原理
- 深入Java集合学习系列:LinkedHashSet的实现原理
- 深入理解Java集合之迭代器Iterator