C Create Secure Stack of Stack Storage Structure

  • 2021-11-13 02:25:06
  • OfStack

In C #, there are many structures used for storage, such as DataTable, DataSet, List, Dictionary, Stack, etc. There are differences in storage methods adopted by various structures, and their efficiency must have their own advantages and disadvantages. Now introduce a last-in first-out data structure.

When it comes to storage structure, we use it more in our projects. For Task storage structure, stack and queue are similar structures, and different methods are adopted when using them. The stack (Stack) in C # is the memory space allocated during compilation, so the size of the stack must be clearly defined in your code; Heap is the memory space dynamically allocated during the running of a program. You can determine the size of heap memory to be allocated according to the running condition of the program.

In C #, the stack usually holds the steps that our code executes. The reference types in C # are stored on the stack, and each thread (Thread) maintains its own dedicated thread stack while the program is running. When a method is called, the main thread begins to look for the called method in the metadata of its assembly, then compiles it immediately through JIT and puts the result (1 is generally a native CPU instruction) on the top of the stack. CPU fetches instructions from the top of the stack through the bus and drives the program to execute.

The data structure of stack is briefly introduced above. Now look at the underlying method of implementing stack structure under C #:


  /// <summary>
  ///  Initialization  <see cref="T:System.Collections.Generic.Stack`1"/>  Class, which is empty and has the default initial capacity. 
  /// </summary>
  [__DynamicallyInvokable]
  public Stack();
  /// <summary>
  ///  Initialization  <see cref="T:System.Collections.Generic.Stack`1"/>  Class, which is empty and has the specified initial capacity or the default initial capacity, where the larger 1 A). 
  /// </summary>
  /// <param name="capacity"><see cref="T:System.Collections.Generic.Stack`1"/>  The number of initial elements that can be contained. </param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="capacity"/> is less than zero.</exception>
  [__DynamicallyInvokable]
  public Stack(int capacity);
  /// <summary>
  ///  Initialization  <see cref="T:System.Collections.Generic.Stack`1"/>  Class that contains elements copied from the specified collection and has sufficient capacity to accommodate the copied elements. 
  /// </summary>
  /// <param name="collection"> The collection from which elements are copied. </param><exception cref="T:System.ArgumentNullException"><paramref name="collection"/> is null.</exception>
  [__DynamicallyInvokable]
  public Stack(IEnumerable<T> collection);

The above is an introduction to some methods of stack, because the safety of threads will be considered while operating data storage.

As the basic unit of operating system executing program, process owns the resources of application program, process contains threads, process resources are shared by threads, and threads do not own resources. Threads are divided into foreground threads and background threads, and new threads created by Thread class are foreground threads by default. When all foreground threads are closed, all background threads are terminated without throwing an exception.

Next, look at the ReaderWriterLockSlim class 1:


  /// <summary>
 /// 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问。
 /// </summary>
 [__DynamicallyInvokable]
 [HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)]
 [HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
 public class ReaderWriterLockSlim : IDisposable
 {
  /// <summary>
  /// 使用默认属性值初始化 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 类的新实例。
  /// </summary>
  [__DynamicallyInvokable]
  public ReaderWriterLockSlim();
  /// <summary>
  /// 在指定锁定递归策略的情况下初始化 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 类的新实例。
  /// </summary>
  /// <param name="recursionPolicy">枚举值之1,用于指定锁定递归策略。</param>
  [__DynamicallyInvokable]
  public ReaderWriterLockSlim(LockRecursionPolicy recursionPolicy);
  /// <summary>
  /// 尝试进入读取模式锁定状态。
  /// </summary>
  /// <exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入读取的模式。- 或 -当它已经包含写入锁时,当前线程可能不会获取读的锁定。- 或 -递归数将超出该计数器的容量。此限制是很大的应用程序应永远不会遇到它。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception>
  [__DynamicallyInvokable]
  public void EnterReadLock();
  /// <summary>
  /// 尝试进入读取模式锁定状态,可以选择超时时间。
  /// </summary>
  /// 
  /// <returns>
  /// 如果调用线程已进入读取模式,则为 true;否则为 false。
  /// </returns>
  /// <param name="timeout">等待的间隔;或为 -1 毫秒,表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="timeout"/> 为负数,但它不等于-1 毫秒为单位),这是唯1允许的值为负。- 或 -值 <paramref name="timeout"/> 大于 <see cref="F:System.Int32.MaxValue"/> 毫秒为单位)。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception>
  [__DynamicallyInvokable]
  public bool TryEnterReadLock(TimeSpan timeout);
  /// <summary>
  /// 尝试进入读取模式锁定状态,可以选择整数超时时间。
  /// </summary>
  /// 
  /// <returns>
  /// 如果调用线程已进入读取模式,则为 true;否则为 false。
  /// </returns>
  /// <param name="millisecondsTimeout">等待的毫秒数,或为 -1 (<see cref="F:System.Threading.Timeout.Infinite"/>),表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="millisecondsTimeout"/> 为负数,但它不是等于 <see cref="F:System.Threading.Timeout.Infinite"/> (-1),这是唯1允许的值为负。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception>
  [__DynamicallyInvokable]
  public bool TryEnterReadLock(int millisecondsTimeout);
  /// <summary>
  /// 尝试进入写入模式锁定状态。
  /// </summary>
  /// <exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已在任何模式下进入该锁。- 或 -当前线程已进入读取的模式,因此尝试进入锁定状态写模式,则会创建导致死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception>
  [__DynamicallyInvokable]
  public void EnterWriteLock();
  /// <summary>
  /// 尝试进入写入模式锁定状态,可以选择超时时间。
  /// </summary>
  /// 
  /// <returns>
  /// 如果调用线程已进入写入模式,则为 true;否则为 false。
  /// </returns>
  /// <param name="timeout">等待的间隔;或为 -1 毫秒,表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -当前线程最初在读取模式中,输入该锁,因此尝试进入写入模式会创建导致死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="timeout"/> 为负数,但它不等于-1 毫秒为单位),这是唯1允许的值为负。- 或 -值 <paramref name="timeout"/> 大于 <see cref="F:System.Int32.MaxValue"/> 毫秒为单位)。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception>
  [__DynamicallyInvokable]
  public bool TryEnterWriteLock(TimeSpan timeout);
  /// <summary>
  /// 尝试进入写入模式锁定状态,可以选择超时时间。
  /// </summary>
  /// 
  /// <returns>
  /// 如果调用线程已进入写入模式,则为 true;否则为 false。
  /// </returns>
  /// <param name="millisecondsTimeout">等待的毫秒数,或为 -1 (<see cref="F:System.Threading.Timeout.Infinite"/>),表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -当前线程最初在读取模式中,输入该锁,因此尝试进入写入模式会创建导致死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="millisecondsTimeout"/> 为负数,但它不是等于 <see cref="F:System.Threading.Timeout.Infinite"/> (-1),这是唯1允许的值为负。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception>
  [__DynamicallyInvokable]
  public bool TryEnterWriteLock(int millisecondsTimeout);
  /// <summary>
  /// 尝试进入可升级模式锁定状态。
  /// </summary>
  /// <exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已在任何模式下进入该锁。- 或 -当前线程已进入读取的模式,因此尝试进入可升级模式将有死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception>
  [__DynamicallyInvokable]
  public void EnterUpgradeableReadLock();
  /// <summary>
  /// 尝试进入可升级模式锁定状态,可以选择超时时间。
  /// </summary>
  /// 
  /// <returns>
  /// 如果调用线程已进入可升级模式,则为 true;否则为 false。
  /// </returns>
  /// <param name="timeout">等待的间隔;或为 -1 毫秒,表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -当前线程最初在读取模式中,输入该锁,因此尝试进入可升级模式会创建导致死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="timeout"/> 为负数,但它不等于-1 毫秒为单位),这是唯1允许的值为负。- 或 -值 <paramref name="timeout"/> 大于 <see cref="F:System.Int32.MaxValue"/> 毫秒为单位)。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception>
  [__DynamicallyInvokable]
  public bool TryEnterUpgradeableReadLock(TimeSpan timeout);
  /// <summary>
  /// 尝试进入可升级模式锁定状态,可以选择超时时间。
  /// </summary>
  /// 
  /// <returns>
  /// 如果调用线程已进入可升级模式,则为 true;否则为 false。
  /// </returns>
  /// <param name="millisecondsTimeout">等待的毫秒数,或为 -1 (<see cref="F:System.Threading.Timeout.Infinite"/>),表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -当前线程最初在读取模式中,输入该锁,因此尝试进入可升级模式会创建导致死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="millisecondsTimeout"/> 为负数,但它不是等于 <see cref="F:System.Threading.Timeout.Infinite"/> (-1),这是唯1允许的值为负。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception>
  [__DynamicallyInvokable]
  public bool TryEnterUpgradeableReadLock(int millisecondsTimeout);
  /// <summary>
  /// 减少读取模式的递归计数,并在生成的计数为 0(零)时退出读取模式。
  /// </summary>
  /// <exception cref="T:System.Threading.SynchronizationLockException">在读取模式中,当前线程不已进入该锁。</exception>
  [__DynamicallyInvokable]
  public void ExitReadLock();
  /// <summary>
  /// 减少写入模式的递归计数,并在生成的计数为 0(零)时退出写入模式。
  /// </summary>
  /// <exception cref="T:System.Threading.SynchronizationLockException">当前线程不已进入写入模式的锁定。</exception>
  [__DynamicallyInvokable]
  public void ExitWriteLock();
  /// <summary>
  /// 减少可升级模式的递归计数,并在生成的计数为 0(零)时退出可升级模式。
  /// </summary>
  /// <exception cref="T:System.Threading.SynchronizationLockException">当前线程不已进入可升级模式的锁定。</exception>
  [__DynamicallyInvokable]
  public void ExitUpgradeableReadLock();
  /// <summary>
  /// 释放 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 类的当前实例所使用的所有资源。
  /// </summary>
  /// <exception cref="T:System.Threading.SynchronizationLockException"><see cref="P:System.Threading.ReaderWriterLockSlim.WaitingReadCount"/> 是大于零。- 或 -<see cref="P:System.Threading.ReaderWriterLockSlim.WaitingUpgradeCount"/> 是大于零。- 或 -<see cref="P:System.Threading.ReaderWriterLockSlim.WaitingWriteCount"/> 是大于零。</exception><filterpriority>2</filterpriority>
  [__DynamicallyInvokable]
  public void Dispose();
  /// <summary>
  /// 获取1个值,该值指示当前线程是否已进入读取模式的锁定状态。
  /// </summary>
  /// 
  /// <returns>
  /// 如果当前线程已进入读取模式,则为 true;否则为 false。
  /// </returns>
  /// <filterpriority>2</filterpriority>
  [__DynamicallyInvokable]
  public bool IsReadLockHeld { [__DynamicallyInvokable] get; }
  /// <summary>
  /// 获取1个值,该值指示当前线程是否已进入可升级模式的锁定状态。
  /// </summary>
  /// 
  /// <returns>
  /// 如果当前线程已进入可升级模式,则为 true;否则为 false。
  /// </returns>
  /// <filterpriority>2</filterpriority>
  [__DynamicallyInvokable]
  public bool IsUpgradeableReadLockHeld { [__DynamicallyInvokable] get; }
  /// <summary>
  /// 获取1个值,该值指示当前线程是否已进入写入模式的锁定状态。
  /// </summary>
  /// 
  /// <returns>
  /// 如果当前线程已进入写入模式,则为 true;否则为 false。
  /// </returns>
  /// <filterpriority>2</filterpriority>
  [__DynamicallyInvokable]
  public bool IsWriteLockHeld { [__DynamicallyInvokable] get; }
  /// <summary>
  /// 获取1个值,该值指示当前 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象的递归策略。
  /// </summary>
  /// 
  /// <returns>
  /// 枚举值之1,用于指定锁定递归策略。
  /// </returns>
  [__DynamicallyInvokable]
  public LockRecursionPolicy RecursionPolicy { [__DynamicallyInvokable] get; }
  /// <summary>
  /// 获取已进入读取模式锁定状态的独有线程的总数。
  /// </summary>
  /// 
  /// <returns>
  /// 已进入读取模式锁定状态的独有线程的数量。
  /// </returns>
  [__DynamicallyInvokable]
  public int CurrentReadCount { [__DynamicallyInvokable] get; }
  /// <summary>
  /// 获取当前线程进入读取模式锁定状态的次数,用于指示递归。
  /// </summary>
  /// 
  /// <returns>
  /// 如果当前线程未进入读取模式,则为 0(零);如果线程已进入读取模式但却不是以递归方式进入的,则为 1;或者如果线程已经以递归方式进入锁定模式 n - 1 次,则为 n。
  /// </returns>
  /// <filterpriority>2</filterpriority>
  [__DynamicallyInvokable]
  public int RecursiveReadCount { [__DynamicallyInvokable] get; }
  /// <summary>
  /// 获取当前线程进入可升级模式锁定状态的次数,用于指示递归。
  /// </summary>
  /// 
  /// <returns>
  /// 如果当前线程没有进入可升级模式,则为 0;如果线程已进入可升级模式却不是以递归方式进入的,则为 1;或者如果线程已经以递归方式进入可升级模式 n - 1 次,则为 n。
  /// </returns>
  /// <filterpriority>2</filterpriority>
  [__DynamicallyInvokable]
  public int RecursiveUpgradeCount { [__DynamicallyInvokable] get; }
  /// <summary>
  /// 获取当前线程进入写入模式锁定状态的次数,用于指示递归。
  /// </summary>
  /// 
  /// <returns>
  /// 如果当前线程没有进入写入模式,则为 0;如果线程已进入写入模式却不是以递归方式进入的,则为 1;或者如果线程已经以递归方式进入写入模式 n - 1 次,则为 n。
  /// </returns>
  /// <filterpriority>2</filterpriority>
  [__DynamicallyInvokable]
  public int RecursiveWriteCount { [__DynamicallyInvokable] get; }
  /// <summary>
  /// 获取等待进入读取模式锁定状态的线程总数。
  /// </summary>
  /// 
  /// <returns>
  /// 等待进入读取模式的线程总数。
  /// </returns>
  /// <filterpriority>2</filterpriority>
  [__DynamicallyInvokable]
  public int WaitingReadCount { [__DynamicallyInvokable] get; }
  /// <summary>
  /// 获取等待进入可升级模式锁定状态的线程总数。
  /// </summary>
  /// 
  /// <returns>
  /// 等待进入可升级模式的线程总数。
  /// </returns>
  /// <filterpriority>2</filterpriority>
  [__DynamicallyInvokable]
  public int WaitingUpgradeCount { [__DynamicallyInvokable] get; }
  /// <summary>
  /// 获取等待进入写入模式锁定状态的线程总数。
  /// </summary>
  /// 
  /// <returns>
  /// 等待进入写入模式的线程总数。
  /// </returns>
  /// <filterpriority>2</filterpriority>
  [__DynamicallyInvokable]
  public int WaitingWriteCount { [__DynamicallyInvokable] get; }
 }

The above is a brief introduction to the related knowledge of Stack and threads. Now, let's introduce 1 thread-safe Stack:


 /// <summary>
  ///  Represents a LIFO safe set of objects ( Stack structure )
  /// </summary>
  /// <typeparam name="T"></typeparam>
  public class TStack<T> : IEnumerable<T>, ICollection
  {
    /// <summary>
    ///  Internal stack 
    /// </summary>
    private readonly Stack<T> _mStack;

    /// <summary>
    ///  Lock access stack ( Used to manage the locked state of resource access, enabling multithreaded read or exclusive write access. )
    /// </summary>
    private readonly ReaderWriterLockSlim _lockStack = new ReaderWriterLockSlim();

    /// <summary>
    ///  For use only SyncRoot Attribute 
    /// </summary>
    private readonly object _objSyncRoot = new object();

    // Variables
    /// <summary>
    ///  Initialization 1 New instances  <see cref="TStack{T}"/> class.
    /// </summary>
    public TStack()
    {
      _mStack = new Stack<T>();
    }

    /// <summary>
    ///  Initialization 1 New instances  <see cref="TStack{T}"/> class.
    /// </summary>
    /// <param name="col">
    ///  Start collection 
    /// </param>
    public TStack(IEnumerable<T> col)
    {
      _mStack = new Stack<T>(col);
    }

    // Init
    /// <summary>
    ///  Get enumerator 
    /// </summary>
    public IEnumerator<T> GetEnumerator()
    {
      Stack<T> localStack = null;

      //  Initialize enumerator 
      _lockStack.PerformUsingReadLock(() =>
      {
        //  Create 1 A m_tlist Copy 
        localStack = new Stack<T>(_mStack);
      });

      //  Get enumerator 
      foreach (T item in localStack)
        yield return item;
    }


    /// <summary>
    ///  Get enumerator 
    /// </summary>
    IEnumerator IEnumerable.GetEnumerator()
    {
      Stack<T> localStack = null;

      //  Initialize enumerator 
      _lockStack.PerformUsingReadLock(() =>
      {
        //  Create 1 A m_TList Copy of 
        localStack = new Stack<T>(_mStack);
      });

      //  Get enumerator 
      foreach (T item in localStack)
        yield return item;
    }


    /// <summary>
    ///  Copy to 1 Array of numbers 
    /// </summary>
    /// <param name="array"></param>
    /// <param name="index"></param>
    public void CopyTo(Array array, int index)
    {
      _lockStack.PerformUsingReadLock(() => _mStack.ToArray().CopyTo(array, index));
    }

    /// <summary>
    /// Number of items on the stack 
    /// </summary>
    public int Count
    {
      get
      {
        return _lockStack.PerformUsingReadLock(() => _mStack.Count);
      }
    }

    /// <summary>
    ///  Always true 
    /// </summary>
    public bool IsSynchronized
    {
      get { return true; }
    }

    /// <summary>
    /// Synchronous root 
    /// </summary>
    public object SyncRoot
    {
      get { return _objSyncRoot; }
    }


    /// <summary>
    /// Clear the collection 
    /// </summary>
    public void Clear()
    {
      _lockStack.PerformUsingWriteLock(() => _mStack.Clear());
    }

    // Clear
    /// <summary>
    /// If the item is on the stack; Otherwise, true
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    public bool Contains(T item)
    {
      return _lockStack.PerformUsingReadLock(() => _mStack.Contains(item));
    }

    //  Include 
    /// <summary>
    ///  Returns the top item on the stack without deleting it from the stack 
    /// </summary>
    /// <returns></returns>
    public T Peek()
    {
      return _lockStack.PerformUsingReadLock(() => _mStack.Peek());
    }

    // Peek
    /// <summary>
    /// Delete and return the top item on the stack 
    /// </summary>
    /// <returns></returns>
    public T Pop()
    {
      return _lockStack.PerformUsingWriteLock(() => _mStack.Pop());
    }

    // Pop
    /// <summary>
    ///  Will 1 Items inserted into the stack 
    /// </summary>
    /// <param name="item"></param>
    public void Push(T item)
    {
      _lockStack.PerformUsingWriteLock(() => _mStack.Push(item));
    }

    // Push
    /// <summary>
    /// Convert a stack to an array 
    /// </summary>
    /// <returns></returns>
    public T[] ToArray()
    {
      return _lockStack.PerformUsingReadLock(() => _mStack.ToArray());
    }

    // ToArray
    /// <summary>
    ///  Set the capacity to the actual number of elements in the stack 
    /// </summary>
    public void TrimExcess()
    {
      _lockStack.PerformUsingWriteLock(() => _mStack.TrimExcess());
    }
  }

The above operation method inherits IEnumerable < T > , ICollection two interfaces. If you are interested, you can study IEnumerable < T > , ICollection two interfaces for a detailed understanding.


Related articles: