实现自定义通用列表/队列/堆栈组合的有效方法

时间:2012-09-20 06:35:36

标签: c# .net list stack queue

我发现不止一次需要将泛型集合在一个时间点作为列表处理,在另一个时间作为堆栈或队列处理。对于我正在开发的应用程序,使用三个单独的对象没有意义。

我能想到的最简单的解决方案是在标准列表上实现Queue / Dequeue / Push / Pop / Peek功能。另外(未包含在下面的代码中),在T上应用了接口约束,允许类维护每个列表,队列和堆栈的位置/序数索引。

public class List<T>:
    System.Collections.Generic.List<T>
{
    private object SyncRoot = new object();

    public void Enqueue (T item)
    {
        lock (this.SyncRoot)
        {
            this.Add(item);
        }
    }

    public T Dequeue ()
    {
        T item = default(T);

        lock (this.SyncRoot)
        {
            if (this.Count > 0)
            {
                item = this [0];
                this.RemoveAt(0);
            }
        }

        return (item);
    }

    public void Push (T item)
    {
        lock (this.SyncRoot)
        {
            this.Add(item);
        }
    }

    public T Pop ()
    {
        T item = default(T);

        lock (this.SyncRoot)
        {
            if (this.Count > 0)
            {
                item = this [this.Count - 1];
                this.RemoveAt(this.Count - 1);
            }
        }

        return (item);
    }

    public T PeekQueue ()
    {
        T item = default(T);

        lock (this.SyncRoot)
        {
            if (this.Count > 0)
            {
                item = this [0];
            }
        }

        return (item);
    }

    public T PeekStack ()
    {
        T item = default(T);

        lock (this.SyncRoot)
        {
            if (this.Count > 0)
            {
                item = this [this.Count - 1];
            }
        }

        return (item);
    }
}
  • 由于这是一个粗略的,即时实现,我不确定要注意哪些角落情况,因此会喜欢指向任何现有此类实现的指针或链接。
  • 其次,我对非常大的名单上的表现持怀疑态度。是否比使用LinkedList更大的列表更好地继承List。就我而言,添加/删除项目的优先级高于枚举列表。

2 个答案:

答案 0 :(得分:2)

以下是如何使用扩展方法来实现类似行为... http://weblogs.asp.net/bsimser/archive/2011/01/13/generic-pop-and-push-for-list-lt-t-gt.aspx

  

Generic Pop and Push for List

     

这是我用来扩展通用List类的小片段   与Stack类相似的功能。

     

Stack类很棒,但它存在于自己的世界之下   System.Object的。拥有可以执行此操作的List是不是很好   相同?这是代码:

public static class ExtensionMethods    
{ 
    public static T Pop<T>(this List<T> theList)    
    {              
        var local = theList[theList.Count - 1];    
        theList.RemoveAt(theList.Count - 1);    
        return local;   
     }

     public static void Push<T>(this List<T> theList, T item)   
     {   
        theList.Add(item);   
     }   
}
  

这是一个简单的扩展,但我发现它很有用,希望你能   太!享受。

也是扩展方法的链接 http://msdn.microsoft.com/en-us/library/bb383977.aspx

答案 1 :(得分:0)

我猜你必须使用数组作为内部数据存储,如何在.NET List和其他泛型中实现它。例如,由于无法处理itnernal数组中的所有元素而不是开始索引移动,因此代码出列效率低下。人们可以在ILSpy中看到C#反编译:

// System.Collections.Generic.List<T>
/// <summary>Removes the element at the specified index of the <see cref="T:System.Collections.Generic.List`1" />.</summary>
/// <param name="index">The zero-based index of the element to remove.</param>
/// <exception cref="T:System.ArgumentOutOfRangeException">
///   <paramref name="index" /> is less than 0.-or-<paramref name="index" /> is equal to or greater than <see cref="P:System.Collections.Generic.List`1.Count" />.</exception>
public void RemoveAt(int index)
{
    if (index >= this._size)
    {
        ThrowHelper.ThrowArgumentOutOfRangeException();
    }
    this._size--;
    if (index < this._size)
    {
        Array.Copy(this._items, index + 1, this._items, index, this._size - index);
    }
    this._items[this._size] = default(T);
    this._version++;
}

其他功能也可以改进一点。

此外,我注意到.NET Stack通用实现比List通用实现工作缓慢。我假设这是因为分配时提取的最后一个元素的默认值,与List:

不同
// System.Collections.Generic.Stack<T>
/// <summary>Removes and returns the object at the top of the <see cref="T:System.Collections.Generic.Stack`1" />.</summary>
/// <returns>The object removed from the top of the <see cref="T:System.Collections.Generic.Stack`1" />.</returns>
/// <exception cref="T:System.InvalidOperationException">The <see cref="T:System.Collections.Generic.Stack`1" /> is empty.</exception>
public T Pop()
{
    if (this._size == 0)
    {
        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyStack);
    }
    this._version++;
    T result = this._array[--this._size];
    this._array[this._size] = default(T);
    return result;
}