2

ジェネリックコレクションを、ある時点ではリストとして扱い、別の時点ではスタックまたはキューとして扱う必要がある場合が複数あります。私が現在開発しているアプリケーションの場合、3つの別々のオブジェクトを使用することは意味がありません。

私が考えることができる最も簡単な解決策は、標準のリストにキュー/デキュー/プッシュ/ポップ/ピーク関数を実装することでした。また(以下のコードには含まれていません)、インターフェイス制約が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から継承する方が適切ですか。私の場合、リストを列挙するよりもアイテムの追加/削除の方が優先されます。
4

2 に答える 2

2

拡張メソッドを使用して同様の動作を実現する方法は次のとおりです... http: //weblogs.asp.net/bsimser/archive/2011/01/13/generic-pop-and-push-for-list-lt-t-gt .aspx

ジェネリックポップアンドプッシュフォーリスト

これは、一般的なListクラスを拡張して、Stackクラスと同様の機能を持つようにするために使用する小さなスニペットです。

Stackクラスは素晴らしいですが、System.Objectの下で独自の世界に存在します。同じことができるリストがあるといいと思いませんか?コードは次のとおりです。

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

于 2012-09-20T07:45:45.353 に答える
0

配列は、内部データの格納として、.NETリストやその他のジェネリックスでどのように実装されているかを使用する必要があると思います。たとえば、インデックスの移動を開始する代わりに、内部配列内のすべての要素を無用に処理するため、コードのデキューは非効率的です。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;
}
于 2012-09-20T07:07:27.647 に答える