[corefx注释说]-System.Collections.Generic.Stack<T>

原创 2015年07月08日 02:48:02

对C#里边的基础类库有充分的好奇心,所以就心血来潮写一下,这个就不定期更新了,想什么时候写就什么时候写好了。这里弱弱的吐槽一下CSDN的博客。为了以防万一,会在我其他的博客做一下备份。

废话不多说 切入正题:
github上的源代码

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

这里的引用没什么好解释的,Stack仅依赖于System,剩下的两个引用是用来分析测试的。

类的声明


[DebuggerTypeProxy(typeof(StackDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
public class Stack<T> : IEnumerable<T>,
    System.Collections.ICollection,
    IReadOnlyCollection<T>

Attributes没什么好解释的,用在Debug里。
这里声明Stack这样一个泛型类,继承IEnumerable< T >,ICollection, IReadOnlyCollection< T >。三个接口。说明这个类支持foreach循环。是一个只读集合。

字段

private T[] _array;     // Storage for stack elements
private int _size;           // Number of items in the stack.
private int _version;        // Used to keep enumerator in sync w/ collection.
private Object _syncRoot;

private const int DefaultCapacity = 4;

这里是它的字段
包括:栈内元素存储数组,栈内元素个数计数器,和用于同步的一些变量。
并且提供了一个默认的容量大小(4)


        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Stack"]/*' />
        public Stack()
        {
            _array = Array.Empty<T>();
        }

        // Create a stack with a specific initial capacity.  The initial capacity
        // must be a non-negative number.
        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Stack1"]/*' />
        public Stack(int capacity)
        {
            if (capacity < 0)
                throw new ArgumentOutOfRangeException("capacity", SR.ArgumentOutOfRange_NeedNonNegNumRequired);
            _array = new T[capacity];
        }

        // Fills a Stack with the contents of a particular collection.  The items are
        // pushed onto the stack in the same order they are read by the enumerator.
        //
        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Stack2"]/*' />
        public Stack(IEnumerable<T> collection)
        {
            if (collection == null)
                throw new ArgumentNullException("collection");
            _array = EnumerableHelpers.ToArray(collection, out _size);
        }

这里是是它的三个构造方法:
第一种构造方法是直接构造一个空的存储数组,至于其它的字段就不管了。(值类型留给CLR就好辣!~)
第二种构造方法是构造一个具有初始容量的存储数组。并且对容量大小做了相应的判断(必须是自然数)
第三种构造方法是复制一个集合到自己的存储数组。并且对源数据集合进行检查(不得为null)

属性

        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Count"]/*' />
        public int Count
        {
            get { return _size; }
        }

        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.IsSynchronized"]/*' />
        bool System.Collections.ICollection.IsSynchronized
        {
            get { return false; }
        }

        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.SyncRoot"]/*' />
        Object System.Collections.ICollection.SyncRoot
        {
            get
            {
                if (_syncRoot == null)
                {
                    System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null);
                }
                return _syncRoot;
            }
        }

接下来是三个属性,没什么好说的,一个是获取集合内元素个数,剩下的两个是敷衍同步用的。。。

方法

void clean() //清除

具体作用是移除在栈内的所有元素。

        // Removes all Objects from the Stack.
        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Clear"]/*' />
        public void Clear()
        {
            Array.Clear(_array, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
            _size = 0;
            _version++;
        }

这里要提及的是并不需要具体的对栈内对象进行深层次的清理工作。垃圾回收会重新清理这些资源的。

bool Contains(T) //判断是否存在该元素

        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Contains"]/*' />
        public bool Contains(T item)
        {
            int count = _size;

            EqualityComparer<T> c = EqualityComparer<T>.Default;
            while (count-- > 0)
            {
                if (((Object)item) == null)
                {
                    if (((Object)_array[count]) == null)
                        return true;
                }
                else if (_array[count] != null && c.Equals(_array[count], item))
                {
                    return true;
                }
            }
            return false;
        }

这里的代码让人感觉回到了Hack time。这里要注意的是 Equals和 == 是不一样的,我这里就不说了(容易跑题),可以谷哥度娘找到这里的区别。

void CopyTo(T[], int) //将栈内元素拷贝到指定的数组中

        // Copies the stack into an array.
        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.CopyTo"]/*' />
        public void CopyTo(T[] array, int arrayIndex)
        {
            if (array == null)
            {
                throw new ArgumentNullException("array");
            }

            if (arrayIndex < 0 || arrayIndex > array.Length)
            {
                throw new ArgumentOutOfRangeException("arrayIndex", SR.ArgumentOutOfRange_NeedNonNegNum);
            }

            if (array.Length - arrayIndex < _size)
            {
                throw new ArgumentException(SR.Argument_InvalidOffLen);
            }

            if (array != _array)
            {
                int srcIndex = 0;
                int dstIndex = arrayIndex + _size;
                for (int i = 0; i < _size; i++)
                    array[--dstIndex] = _array[srcIndex++];
            }
            else
            {
                // Legacy fallback in case we ever end up copying within the same array.
                Array.Copy(_array, 0, array, arrayIndex, _size);
                Array.Reverse(array, arrayIndex, _size);
            }
        }

看源代码我们会知道,你要拷贝到的数组中,从该数组的接收位置算起,长度必须足够容纳下栈内的所有元素。并且为了贯彻落实好栈的FILO的优良品质,复制时需要严肃认真地处理好顺序(也就是说复制过去的是逆序的)。这里很奇怪的是对待相同数组和不同数组的执行差异(对待相同数组估计是要做类内扩展用)

void System.Collections.ICollection.CopyTo(Array array, int arrayIndex) 复制到指定数组中

void System.Collections.ICollection.CopyTo(Array array, int arrayIndex)
        {
            if (array == null)
            {
                throw new ArgumentNullException("array");
            }

            if (array.Rank != 1)
            {
                throw new ArgumentException(SR.Arg_RankMultiDimNotSupported);
            }

            if (array.GetLowerBound(0) != 0)
            {
                throw new ArgumentException(SR.Arg_NonZeroLowerBound);
            }

            if (arrayIndex < 0 || arrayIndex > array.Length)
            {
                throw new ArgumentOutOfRangeException("arrayIndex", SR.ArgumentOutOfRange_NeedNonNegNum);
            }

            if (array.Length - arrayIndex < _size)
            {
                throw new ArgumentException(SR.Argument_InvalidOffLen);
            }

            try
            {
                Array.Copy(_array, 0, array, arrayIndex, _size);
                Array.Reverse(array, arrayIndex, _size);
            }
            catch (ArrayTypeMismatchException)
            {
                throw new ArgumentException(SR.Argument_InvalidArrayType);
            }
        }

这里判断了一下矩阵的秩以及下标和是否越界的情况。还是有维护Stack的FILO的特征。

Enumerator GetEnumerator() 返回用于枚举的对象

        // Returns an IEnumerator for this Stack.
        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.GetEnumerator"]/*' />
        public Enumerator GetEnumerator()
        {
            return new Enumerator(this);
        }

        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.IEnumerable.GetEnumerator"]/*' />
        /// <internalonly/>
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return new Enumerator(this);
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new Enumerator(this);
        }

void TrimExcess() 节省Stack空间

        public void TrimExcess()
        {
            int threshold = (int)(((double)_array.Length) * 0.9);
            if (_size < threshold)
            {
                Array.Resize(ref _array, _size);
                _version++;
            }
        }

这里有一个“缓冲”的判断,即threshold如果是小于数组的物理长度的百分之90的时候才压缩,否则就不压缩了。这个比较重要,参见下面的数组容量递增规则。

T Peek() 返回栈顶元素

        // Returns the top object on the stack without removing it.  If the stack
        // is empty, Peek throws an InvalidOperationException.
        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Peek"]/*' />
        public T Peek()
        {
            if (_size == 0)
                throw new InvalidOperationException(SR.InvalidOperation_EmptyStack);
            return _array[_size - 1];
        }

T Pop() 弹出栈

        // Pops an item from the top of the stack.  If the stack is empty, Pop
        // throws an InvalidOperationException.
        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Pop"]/*' />
        public T Pop()
        {
            if (_size == 0)
                throw new InvalidOperationException(SR.InvalidOperation_EmptyStack);
            _version++;
            T item = _array[--_size];
            _array[_size] = default(T);     // Free memory quicker.
            return item;
        }

这里又感觉回到了engineer time(并不只做一件事)

void Push(T) 推入栈

        // Pushes an item to the top of the stack.
        // 
        /// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Push"]/*' />
        public void Push(T item)
        {
            if (_size == _array.Length)
            {
                Array.Resize(ref _array, (_array.Length == 0) ? DefaultCapacity : 2 * _array.Length);
            }
            _array[_size++] = item;
            _version++;
        }

这里关注一下它的推入规则,当存储数组的长度为零时,就设置为4(常量字段中有写),否则就以两倍的递增速度进行递增。

T[] ToArray() 将Stack转化为Array

        public T[] ToArray()
        {
            T[] objArray = new T[_size];
            int i = 0;
            while (i < _size)
            {
                objArray[i] = _array[_size - i - 1];
                i++;
            }
            return objArray;
        }

依旧是贯彻落实好FILO的好特征。

类内结构体

        /// <include file='doc\Stack.uex' path='docs/doc[@for="StackEnumerator"]/*' />
        [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "not an expected scenario")]
        public struct Enumerator : IEnumerator<T>,
            System.Collections.IEnumerator

作用是枚举对象

字段

 private Stack<T> _stack;
 private int _index;
 private int _version;
 private T _currentElement;

这里定义了几个字段,一个是栈,指针,当前指向的元素。

构造方法

internal Enumerator(Stack<T> stack)
{
    _stack = stack;
    _version = _stack._version;
    _index = -2;
    _currentElement = default(T);
}

这里关键在于_version这里。(就是跟stack同步)和index的取值意义。

方法

bool Dispose() 结束枚举
public void Dispose()
{
    _index = -1;
}
bool MoveNext() 移动到下一个元素
/// <include file='doc\Stack.uex' path='docs/doc[@for="StackEnumerator.MoveNext"]/*' />
public bool MoveNext()
{
    bool retval;
    if (_version != _stack._version) throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
    if (_index == -2)
    {  // First call to enumerator.
        _index = _stack._size - 1;
        retval = (_index >= 0);
        if (retval)
            _currentElement = _stack._array[_index];
        return retval;
    }
    if (_index == -1)
    {  // End of enumeration.
        return false;
    }

    retval = (--_index >= 0);
    if (retval)
        _currentElement = _stack._array[_index];
    else
        _currentElement = default(T);
    return retval;
}
T Current 当前元素

这里可以看一下index == -2时是枚举没开始。index == -1时是枚举结束。

/// <include file='doc\Stack.uex' path='docs/doc[@for="StackEnumerator.Current"]/*' />
public T Current
{
    get
    {
        if (_index == -2) throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted);
        if (_index == -1) throw new InvalidOperationException(SR.InvalidOperation_EnumEnded);
        return _currentElement;
    }
}

Object System.Collections.IEnumerator.Current
{
    get
    {
        if (_index == -2) throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted);
        if (_index == -1) throw new InvalidOperationException(SR.InvalidOperation_EnumEnded);
        return _currentElement;
    }
}
Reset()

重置

void System.Collections.IEnumerator.Reset()
{
    if (_version != _stack._version) throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
    _index = -2;
    _currentElement = default(T);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

MSDN:使用泛型 类型“System.Collections.Generic.IComparer <T> ”需要“1”个类型参数”。

今天在学习实现点击listview(视图为Details) 的Column时进行自动排序,查询MSDN给出了一个要自定义ICompare接口的实例;结果实例运行时是抛出错误错误 “ 使用泛型 类型“S...

ASP.Net 之 System.Collections.Generic 下的容器类

System.Collections.Generic.Dictionary//键/值对集合 System.Collections.Generic.KeyValuePair//键/值对结构, 作为 D...

C#泛型集合 using System.Collections.Generic

泛型最常见的用途是泛型集合,命名空间System.Collections.Generic 中包含了一些基于泛型的集合类,使用泛型集合类可以提供更高的类型安全性,还有更高的性能,避免了非泛型集合的重复的...

CS1612: 无法修改“¡°System.Collections.Generic.List.this[int]””的返回值,因为它不是变量。【C# 语言中 struct 的陷阱】

原文地址:http://www.cnblogs.com/skyivben/archive/2010/04/23/1718983.html 假设我们要为某大学写一个工资管理程序。首先是表示员工的 Em...

System.Collections.Generic

using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; ...

System.Collections.Generic 命名空间1

System.Collections.Generic 命名空间包含定义泛型集合的接口和类,泛型集合允许用户创建强类型集合,它能提供比非泛型强类型集合更好的类型安全性和性能。   类 ...

C#泛型集合 using System.Collections.Generic

泛型最常见的用途是泛型集合,命名空间System.Collections.Generic 中包含了一些基于泛型的集合类,使用泛型集合类可以提供更高的类型安全性,还有更高的性能,避免了非泛型集合的重复的...
  • pes605
  • pes605
  • 2013年09月01日 11:24
  • 771

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin

System 包含用于定义常用值和引用数据类型、事件和事件处理程序、接口、属性和处理异常的基础类和基类。其他类提供支持下列操作的服务:数据类型转换,方法参数操作,数学计算,远程和本地程序调用,应用程...

collections-generic-4.01_and_looks-2.1.4

  • 2015年12月18日 11:09
  • 805KB
  • 下载

【DataStructure】The description of generic collections

In this blog, generic collections will be talked about  in details.  In the past bacause of shortage...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[corefx注释说]-System.Collections.Generic.Stack<T>
举报原因:
原因补充:

(最多只允许输入30个字)