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

相关文章推荐

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

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

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

为了节省时间,只写一些关注的方法好了,剩下的可以MSDN嘛XD首先是声明部分,表示为队列是一个可用于枚举的只读集合 [DebuggerTypeProxy(typeof(QueueDebugVie...

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

Java的注释说明

在Java里面主要有三种注释:行注释、段落注释、文档注释   1)行注释:行注释也成为单行注释,行注释使用 “//注释文字”的格式来对某一行的代码进行注释或者加以说明 public cla...

在Flash Builder 4.x 中书写符合ASDOC规范的说明注释

概述 本文介绍和总结Flex中的说明注释——ASDOC注释的规范及注意事项。 知识点 ASDOC说明注释可用的说明注释标签可用的HTML标签注释编写注意事项 Flex中说明注释的格式 与其...

php注释说明

php注释说明 2012 年 2 月 1 日 16:42allenLeave a CommentEdit /** * @name 名字 * @abstract 申明变量/类/方法 *...
  • suiye
  • suiye
  • 2012-08-02 22:47
  • 317

2015061507 - 注释说明

注释一般是对代码的说明和补充,如果代码能说明问题可以不添加注释,但是存在一个问题就是你认为表达的很清楚了,也许事实上真是表达很清楚.但是对于别人而言,未必能认为你的代码能表达很清楚.所以若干注释是必要...

Hibernate注释说明

声明实体Bean@Entitypublic class Flight implements Serializable {  Long id;  @Id  public Long getId() { r...

nginx.conf 说明 注释

#Nginx配置文件主要分为4部分:main(全局设置)部分设置的指令将影响其他所有设置;server(主机设置)部分的指令主要用于指定主机和端口;upstream(负载均衡服务器设置)部分指令主要用...

49.windbg----$$(注释说明符)和*(注释行说明符)和.echo

$$(注释说明符) 如果命令开头出现两个美元符号( $$ ),则该行剩下的部分被当成注释,除非碰到分号,$$ 关键字使得后面的文本被忽略掉,直到行末或者碰到分号。分号结束注释;分号后的文本被解析为标...
  • hgy413
  • hgy413
  • 2013-06-13 15:25
  • 1576

C# 注释及说明

using System; /// /// ClassName:SomeClass /// Version:1.0 /// Date:2001/6/21 /// Author:cniter /// ...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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