一、System.Collections名称空间下几个接口表征着集合的功能:

1、IEnumerable:表征着迭代功能

public interface IEnumerable
{ IEnumerator GetEnumerator();
} public interface IEnumerator
{
bool MoveNext();
object Current { get; }
void Reset();
}

注意,IEnumerator也属于System.Collections空间。

2、其它诸如:ICollection IList IDictionary 都表征着相应的集合功能。它们的代码如下:

public interface ICollection : IEnumerable
{
void CopyTo(Array array, int index); int Count { [__DynamicallyInvokable] get; }
} public interface IList : ICollection, IEnumerable
{
// Methods
int Add(object value);
void Clear();
bool Contains(object value);
int IndexOf(object value);
void Insert(int index, object value);
void Remove(object value);
void RemoveAt(int index); } public interface IDictionary : ICollection, IEnumerable
{
// Methods
[__DynamicallyInvokable]
void Add(object key, object value);
[__DynamicallyInvokable]
void Clear();
[__DynamicallyInvokable]
bool Contains(object key);
[__DynamicallyInvokable]
IDictionaryEnumerator GetEnumerator();
[__DynamicallyInvokable]
void Remove(object key); // Properties
bool IsFixedSize { [__DynamicallyInvokable] get; }
bool IsReadOnly { [__DynamicallyInvokable] get; }
object this[object key] { [__DynamicallyInvokable] get; [__DynamicallyInvokable] set; }
ICollection Keys { [__DynamicallyInvokable] get; }
ICollection Values { [__DynamicallyInvokable] get; }
}

上面说的都是接口,它们内部都是些方法声明而已。具体的类,比如System.Array和System.Collections.ArrayList里面才有具体的方法实现。

System.Collections.ArrayList是System.Object对象的集合。

二、创建自己的集合:

一种方式是我们手动实现集合的所有方法,另一种方式是我们继承System.Collections.CollectionBase类。CollectionBase类已经实现了IEnumerable和ICollection、IList接口。

1、在继续之前,我们先来看看CollectionBase是怎么实现的:

[Serializable, ComVisible(true), __DynamicallyInvokable]
public abstract class CollectionBase : IList, ICollection, IEnumerable
{
// Fields
private ArrayList list; // Methods
protected CollectionBase();
protected CollectionBase(int capacity);
public void Clear();
public IEnumerator GetEnumerator();
protected virtual void OnClear();
protected virtual void OnClearComplete();
protected virtual void OnInsert(int index, object value);
protected virtual void OnInsertComplete(int index, object value);
protected virtual void OnRemove(int index, object value);
protected virtual void OnRemoveComplete(int index, object value);
protected virtual void OnSet(int index, object oldValue, object newValue);
protected virtual void OnSetComplete(int index, object oldValue, object newValue);
protected virtual void OnValidate(object value);
public void RemoveAt(int index);
void ICollection.CopyTo(Array array, int index);
int IList.Add(object value);
bool IList.Contains(object value);
int IList.IndexOf(object value);
void IList.Insert(int index, object value);
void IList.Remove(object value); // Properties public int Capacity { get; set; }
public int Count { [__DynamicallyInvokable] get; }
protected ArrayList InnerList { get; }
protected IList List { get; }
bool ICollection.IsSynchronized { get; }
object ICollection.SyncRoot { get; }
bool IList.IsFixedSize { get; }
bool IList.IsReadOnly { get; }
object IList.this[int index] { get; set; }
}

可知,CollectionBase是基于ArrayList的,GetEnumerator便是对IEnumerable接口的实现,它返回了一个IEnumerator,那么这个IEnumerator内部到底做了什么使得ICollection可以迭代(通过foreach)呢,显然,CollectionBase没有做这个工作,这个工作是由ArrayList来做的。具体来说是这样:CollectionBase有一个list数据成员,它不是属性(名称用camel命名法,且没有getter/setter),InnerList也是CollectionBase的属性,这个属性的代码以及GetEnumerator的代码如下:

protected ArrayList InnerList
{
get
{
if (this.list == null)
{
this.list = new ArrayList();
}
return this.list;
}
} public IEnumerator GetEnumerator()
{
return this.InnerList.GetEnumerator();
}

可以看到,确实是基于ArrayList的。
2、那么,我们来看看ArrayList是怎么实现迭代的:

public class ArrayList : IList, ICollection, IEnumerable, ICloneable
{
// Fields
private const int _defaultCapacity = ;
private object[] _items;
private int _size; 。。。 public virtual IEnumerator GetEnumerator()
{
return new ArrayListEnumeratorSimple(this);
} 。。。 private sealed class ArrayListEnumeratorSimple : IEnumerator, ICloneable
{
// Fields
private object currentElement;
private static object dummyObject;
private int index;
[NonSerialized]
private bool isArrayList;
private ArrayList list;
private int version; // Methods
static ArrayListEnumeratorSimple();
internal ArrayListEnumeratorSimple(ArrayList list);
public object Clone();
public bool MoveNext();
public void Reset(); // Properties
public object Current { get; }
} }

可以看到ArrayList自己也没干活,而是把迭代任务交给了自己的一个内部类ArrayListEnumeratorSimple,其中有一个构造的修饰符是internal,意思是这个方法只能在程序集内部调用。该类有一个list成员,这个成员便是当ArrayList的GetEnumerator方法调用时把this,即ArrayList自己传给了ArrayListEnumeratorSimple的构造,从而ArrayListEnumeratorSimple的list也就得到初始化了。具体实现代码如下:

 private sealed class ArrayListEnumeratorSimple : IEnumerator, ICloneable
{
// Fields
private object currentElement;
private static object dummyObject;
private int index;
private bool isArrayList;
private ArrayList list;
private int version; // Methods
static ArrayListEnumeratorSimple()
{
dummyObject = new object();
} internal ArrayListEnumeratorSimple(ArrayList list)
{
this.list = list;
this.index = -;
this.version = list._version;
this.isArrayList = list.GetType() == typeof(ArrayList);
this.currentElement = dummyObject;
} public object Clone(){/*...*/}
public bool MoveNext()
{
if (this.version != this.list._version)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
}
if (this.isArrayList)
{
if (this.index < (this.list._size - ))
{
this.currentElement = this.list._items[++this.index];
return true;
}
this.currentElement = dummyObject;
this.index = this.list._size;
return false;
}
if (this.index < (this.list.Count - ))
{
this.currentElement = this.list[++this.index];
return true;
}
this.index = this.list.Count;
this.currentElement = dummyObject;
return false;
} public void Reset()
{
if (this.version != this.list._version)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
}
this.currentElement = dummyObject;
this.index = -;
} public object Current
{
get
{
object currentElement = this.currentElement;
if (dummyObject != currentElement)
{
return currentElement;
}
if (this.index == -)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumNotStarted"));
}
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumEnded"));
}
} }

迭代的原理很简单:

MoveNext的工作就是将Index加1,然后将新的Index指向的元素设置为当前元素currentElement,这些执行成功就返回true,否则返回false。
Reset的工作就是将Index置为-1。

Current属性则返回当前元素。

3、一个简单的自定义集合:这个就暂时先略了吧,有了上面的分析,我们通过继承CollectionBase的方法去自定义一个集合就很简单了。

三、foreach循环迭代的原理:参考http://li19910722.blog.163.com/blog/static/136856822201359105740400/

只有当一个集合实现了IEnumerable接口,才能在这个集合对象上进行foreach。由参考链接中的内容可知,其实实不实现IEnumerable接口无所谓,只要你有一个GetEnumerator方法返回一个Enumerator即可。要知道的是,Enumerator的MoveNext在将索引加1的同时,返回了true,如果到达界限则返回false,之所以返回bool值,是为了给foreach的in操作作判断用的,为真则执行循环体,否则退出循环。

但这还不够,我还是觉得有些东西没弄明白,比如迭代的时候可以用yield什么的,这其中的原理又是什么呢?看了这篇文章http://jangmon.blogbus.com/logs/36380490.html,总结一下:

foreach (Person p in persons)
{
Console.WriteLine(p);
}
//上面的代码会被C#解析成:
IEnumerator enumerator = persons.GetEnumerator();
while (enumerator.MoveNext())
{
Person p = (Person) enumerator.Current;
Console.WriteLine(p);
}
//可以看出,这和我们上面的说法互补。
//定义一个HelloCollection
public class HelloCollection : IEnumerable
{
public IEnumerator GetEnumerator()
{
yield return "Hello";
yield return "World";
}
} //开始迭代
static void Main(string[] args)
{ HelloCollection helloCollection=new HelloCollection ();
foreach (string s in helloCollection )
{
Console.WriteLine(s);
}
}
//HelloCollection最终转换成的代码
public class HelloCollection : IEnumerable
{
public IEnumerator GetEnumerator()
{
Enumertor enumerator = new Enumerator();
return enumerator;
} public class Enumertor : IEnumerator, IDisposable
{
private int state;
private object current; public Enumertor(int state)
{
this.state = state;
}
}
bool System.Collections .IEnumerator .MoveNext()
{
switch (state)
{
case :
current = "Hello";
state = ;
return true;
case :
current = "World";
state = ;
return true ;
case :
break ;
}
return false ;
} void System.Collections .IEnumerator .Reset()
{
throw new NotSupportedException();
} object System.Collections .IEnumerator .Current
{
get { return current; }
}
void IDisposable.Dispose()
{
}
}

我觉得上篇文章的GetEnumerator方法在返回一个new出的Enumerator的时候,应该将state初始化为0,应该是作者是或者作者所参考的书籍的代码中的一个小错误。
GetEnumerator方法是foreach迭代默认在被迭代集合对象上调用的方法,这是可以定制的:

public class MusicTitles:IEnumerable
{
string[] names = { "Tubular Bells", "Hergest Ridge", "Ommadawn", "Platinum" }; public IEnumerator GetEnumerator() /*顺序迭代*/
{
for (int i = ; i < ; i++)
yield return names[i];
} public IEnumerator Reverse() /*逆序迭代*/
{
for (int i = ; i >= ; i--)
yield return names[i];
}
} static void Main(string[] args)
{ MusicTitles titles = new MusicTitles();
//这个迭代没有指明,则默认就使用被迭代集合的GetEnumerator方法
foreach (string title in titles)
{
Console.WriteLine(title);
} Console.WriteLine();
//这个指明了迭代所用的方法
foreach (string title in titles.Reverse())
{
Console.WriteLine(title);
}
}

四、一点体会:关于迭代,说了上面一堆,又想起Linq查询,大意是只有访问一个Element时才会作真正的查询,不知道Linq跟foreach有什么关系,日后学到了再说,反正有了一点体会,也不知道对不对:foreach跟for的区别在于,for在遍历一个集合的时候,集合中的元素必须是已经存在于内存的,而foreach由于迭代每一个项都走了MoveNext方法,从而我们可以在真正迭代到某元素的时候再临时地在MoveNext里把这个元素查出来(这取决于MoveNext的具体实现了),这似乎有一点延迟加载的味道,不知道和Linq延时查询以及EF的延时加载有什么内存关联,日后再说吧。

C#学习:集合、迭代、泛型(1)的更多相关文章

  1. java学习——集合框架(泛型,Map)

    泛型: ... Map:一次添加一对元素.Collection 一次添加一个元素. Map也称为双列集合,Collection集合称为单列集合. 其实map集合中存储的就是键值对. map集合中必须保 ...

  2. 在Arrays.asList()引发的问题中进一步学习集合与泛型等内容

    前言 最近在网上看到一个问题,情况类似如下(记为问题1): public class Demo { public static void main(String[] args) { System.ou ...

  3. Java_集合与泛型

    Collection 集合,集合是java中提供的一种容器,可以用来存储多个数据.在前面的学习中,我们知道数据多了,可以使用数组存放或者使用ArrayList集合进行存放数据.那么,集合和数组既然都是 ...

  4. Java集合之泛型的使用

    Java集合之泛型的使用 泛型提供了一种轻便灵活的数据操作,数据的安全性相对提高. 泛型提供了对列表元素的约束条件,比如ArrayList有序链表,可存储任意类型的元素. 此处构建一个ArrayLis ...

  5. Json.Net学习.集合序列化.

    只要集合实现了IEnumable接口就可以进行序列化 Json序列化器为序列化及反序列化集合对象提供了良好的支持. ->Serializing 为了序列化一个集合---一个泛型的list,arr ...

  6. C#非泛型集合和泛型集合的超级详解

    C# 泛型集合之非泛型集合类与泛型集合类的对应: ArrayList对应List HashTable对应Dictionary Queue对应Queue Stack对应Stack SortedList对 ...

  7. 【原】Java学习笔记027 - 泛型

    package cn.temptation.test; import java.util.ArrayList; import java.util.Iterator; public class Samp ...

  8. Java集合与泛型中的几个陷阱,你掉进了几个?

    下面我总结了集合.泛型.数组转集合等一些常见的陷进,认真看完,相信你绝对有所收获. 1.List ,List<?> 与 List<Object> 有区别吗? 说实话,我敢保证很 ...

  9. Java集合与泛型中的陷阱

    List,List<Object>区别 List<Integer> t1 = new ArrayList<>(); // 编译通过 List t2 = t1; // ...

  10. redis学习-集合set常用命令

    redis学习-集合set常用命令   1.sadd:添加一个元素到集合中(集合中的元素无序的并且唯一) 2.smembers:查看集合中所有的元素(上图事例) 3.srem:删除结合中指定的元素 4 ...

随机推荐

  1. VB6-系统打印常识

    在一次做图片打印的时候,对位置的调整老是不得法,后来通过CBM666老师的帮助才解决问题,分享以下他给的帮助.     , , picA.Width , picA.Height Printer.End ...

  2. 将TIBCO Host 实例注册为Windows服务

    安装了TIBCO ActiveMatrix BPM及成功创建了ActiveMatrix Administrator 和 BPM Server后,每次都要手动启动tibcohost,比较麻烦,实际上TI ...

  3. Drupal commerce 性能优化

    从开始的时候打开一个页面需要超过9秒的时间到现在可以在3秒内打开,给自己带来了很多欣慰. 开始的时候是认为server性能不足,所以讲aliyun服务器从1核升级到了4核,但是发现升级之后和升级之前是 ...

  4. 2、分布式文件系统---HDFS

    1.HDFS设计前提与目标 (1)硬件错误是常态而不是异常.  错误检测并快速自动恢复是HDFS最核心设计目标 (2)流式数据访问.运行在HDFS上的应用主要是以流式数据读取为主,做批量处理而不是用户 ...

  5. spring ioc aop 原理

    spring ioc aop 原理 spring ioc aop 的原理 spring的IoC容器是spring的核心,spring AOP是spring框架的重要组成部分. 在传统的程序设计中,当调 ...

  6. 扩展pl0编译器设计——总述

    所谓编译器,实际上就是我们编程时将输入的高级语言代码转换成相应的目标代码,从而实现将目标代码转换成汇编码的一种过渡工具. 这种工具根据具体情况不同,可以将不同的高级语言代码转换成不同的目标代码,例如将 ...

  7. 如何解决jenkins中shell脚本明明执行失败却不自行退出,且构建结果仍然显示success的问题??

    首先,需要明确shell命令执行结果$?为0或者非0仅能代表此执行语句是否顺利执行了,例如: 执行语句:adb connect 192.168.XX.XX 执行结果:unable to connect ...

  8. C语言杂记

    strcmp函数是可以和int数字进行比较的 , , , }; puts(ch); if (strcmp("AAA", ch)) { printf("real?true! ...

  9. [JavaScript] 用html5 js实现浏览器全屏

    项目中需要将后台浏览器的窗口全屏,也就是我们点击一个按钮要实现按F11全屏的 效果. 在HTML5中,W3C制定了关于全屏的API,就可以实现全屏幕的效果,也可以 让页面中的图片,视频等全屏目前只有g ...

  10. [转载]MongoDB学习 (五):查询操作符(Query Operators).1st

    本文地址:http://www.cnblogs.com/egger/archive/2013/05/04/3059374.html   欢迎转载 ,请保留此链接๑•́ ₃•̀๑! 查询操作符(Quer ...