[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);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

.Net开源之corefx、coreclr初探(三)

本文介绍利用编译出来的coreclr来执行C#编写的Hello coreclr程序。我的机器环境是Win 7 x64 En,VS2013. (1)编译test程序,根据开发guide,执行build...
  • u013376417
  • u013376417
  • 2015年02月09日 18:26
  • 3584

acm——男人的承诺

男人的承诺 Time Limit: 1000 MS Memory Limit: 65536 K Total Submit: 4546(2410 u...
  • Floris_lovelace
  • Floris_lovelace
  • 2016年12月16日 21:26
  • 236

.Net开源之corefx、coreclr初探(二)

接上文,上周编译coreclr没有通过,我这边编译失败的主要原因是操作系统是x86的,而github上的开发guide,明确的要求windows平台下编译时支持的是x64,我换成了x64电脑进行编译就...
  • u013376417
  • u013376417
  • 2015年02月09日 16:31
  • 1395

vs自动注释add-in插件编写(一)--辅助函数

#define ULONG_PTR _w64 unsigned long#include ......void InsertText(CComQIPtr pTextSelection, CString...
  • yufei_email
  • yufei_email
  • 2015年02月12日 16:13
  • 1328

也说_T、_TEXT、TEXT、L

转载于:http://www.cnblogs.com/sobe/archive/2011/03/14/1984188.html 百度或谷歌一下,有很多大牛早已经写过无数相关的文章说明这几个宏的作用 ...
  • zhouyelihua
  • zhouyelihua
  • 2013年10月08日 23:55
  • 563

VS2010、VS2012、VS2013 代码自动注释插件【2】

VS2010、VS2012、VS2013的代码自动注释插件。安装该插件后,可以在VS的菜单中显示“注释”主菜单,可以给类、函数、成员添加标准的注释,与Doxygen配合使用,可以直接生成项目的注释文档...
  • aoshilang2249
  • aoshilang2249
  • 2015年03月13日 12:50
  • 4161

ssh的注解 说明

全注解SSH  一,hibernate annotation  Class注解:  1. @Entity:表明当前类是一个持久化类  2. @Table(name="team",catalog...
  • dahuaaihuyue
  • dahuaaihuyue
  • 2014年12月16日 15:45
  • 771

junit4单元测试的注释使用说

junit4单元测试的注释使用说 右键项目->properties->Java Build Path->Libraies->Add Library->JUnit->next->JUn...
  • u014692324
  • u014692324
  • 2014年12月31日 11:28
  • 274

注解式读取properties文件中的内容

注解式读取properties文件中的内容:springMvc获取properties文件的注解方式: 需要的jar包:spring-beans-4.1.4.RELEASE.jar 1.首先需要在...
  • xupengbo527
  • xupengbo527
  • 2017年11月14日 10:37
  • 76

彻底解决ubuntu环境下,Qt5.5以上版本无法进行中文注释的问题。

**声明:测试的系统环境为ubuntu14.04/ubuntu16.04 测试qt的版本有:qt5.6.0/qt5.7.0 方法通过测试,qt可以正常输入中文注释。**1. 安装fcitx-fro...
  • qingrenufo
  • qingrenufo
  • 2017年11月20日 17:29
  • 225
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[corefx注释说]-System.Collections.Generic.Stack<T>
举报原因:
原因补充:

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