设为首页 加入收藏

TOP

C#集合类型大揭秘(一)
2018-08-06 10:54:56 】 浏览:308
Tags:集合 类型 揭秘

集合是.NET FCL(Framework Class Library)的重要组成部分,我们平常撸C#代码时免不了和集合打交道,FCL提供了丰富易用的集合类型,给我们撸码提供了极大的便利。正是因为这种与生俱来的便利性,使得我们对集合既熟悉又陌生。很多同学可能一直还是停留在使用的层面上,那么今天我们一起来深入学习一下C#语言中的各种集合。


首先我们看一下 FCL 给我们提供的集合接口:


mark


FCL提供了泛型非泛型两大类集合类型。因为非泛型集合装箱和拆箱带来的性能开销问题,和泛型集合相比,已经变得越来越鸡肋。所以我们也侧重于泛型集合的分析,但是两者差别不大。


mark


IEnumerable接口是所有集合类型的祖宗接口,其作用相当于Object类型之于其它类型。如果某个类型实现了IEnumerable接口,就意味着它可以被迭代访问,也就可以称之为集合类型(可枚举)。IEnumerable接口定义非常简单,只有一个GetEnumerator()方法用于获取IEnumerator类型的迭代器。


mark


我们可以将迭代器想象成数据库的游标,即序列(集合)中的某个位置,迭代器只能在序列(集合)中向前移动。每调用一次MoveNext(),如果序列(集合)中还有下一个元素,则迭代器移动到下一个元素;Current用于获取序列(集合)中的当前元素;因为迭代器调用一次代码只需要获取一个元素,这意味着我们需要确定访问到了序列(集合)中的哪个位置。Reset()用于重置这种状态,但是基本上不会使用Reset()重置状态。


同一个序列(集合)可能同时存在多个迭代器操作,相当于同时对一个集合进行多个遍历。这种情况下可能会出现迭代彼此交错。那么如何解决呢?


集合类不直接支持 IEnumerator
IEnumerator 接口。而是直接支持 IEnumerable接口,其唯一方法是 GetEnumerator,此方法用于返回支持 IEnumerator 的对象。每次调用GetEnumerator()方法时都需要创建一个新的对象,同时迭代器必须保存自身的状态,记录此时已经迭代到哪一个元素。这样迭代器就像是序列中的游标。可以有多个游标,移动其中任何一个都可以枚举集合,与其他迭代器互不影响。


for依赖对 Length 属性和索引运算符 ([]) 的支持。借助 Length 属性,C# 编译器可以使用 for 语句迭代数组中的每个元素。for适用于长度固定且始终支持索引运算符的数组,但并不是所有类型集合的元素数量都是已知的。此外,许多集合类(包括 Stack、Queue 和 Dictionary)都不支持按索引检索元素。因此,需要使用一种更为通用的方法来迭代元素集合。假设可以确定第一个、第二个和最后一个元素,那么就没有必要知道元素数量,也没有必要支持按索引检索元素。foreach在这种背景下应运而生。实际上,foreach内部使用迭代器的MoveNext和Current完成元素的遍历。


List<int> list = new List<int>();
List<int>.Enumerator enumerator = list.GetEnumerator();
try
{
    int number;
    while (enumerator.MoveNext())
    {
        number = enumerator.Current;
        Console.WriteLine(number);
    }
}
finally
{
    enumerator.Dispose();
}


我们可以自己实现IEnumerable接口和IEnumerator接口实现自定义集合。


实现自定义可枚举类型:


public class MySet : IEnumerable
{
    internal object[] values;


    public MySet(object[] values)
    {
        this.values = values;
    }


    public IEnumerator GetEnumerator()
    {
        return new MySetIterator(this);
    }
}


手写实现自定义迭代器:



public class MySetIterator : IEnumerator
{
    MySet set;
    /// <summary>
    /// 保存迭代到的位置
    /// </summary>
    int position;
    internal MySetIterator(MySet set)
    {
        this.set = set;
        position = -1;
    }


    public object Current
    {
        get
        {                 
            if(position==-1||position==set.values.Length)
            {
                throw new  InvalidOperationException();
            }
            int index = position;
            return set.values[index];
        }
    }


    public bool MoveNext()
    {
        if(position!=set.values.Length)
        {
            position++;
        }
        return position < set.

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Socket网络编程入门详述 下一篇数据加密算法--详解DES算法原理与..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目