2011-07-05 24 views
1

我從方法返回IList<T>列表<T>。插入與堆棧<T> .Push

在調用類中,我想在列表/堆棧的開始處插入一個值。

List<T>中插入值比在Stack<T>中推送值慢。但要使用堆棧,我需要解開它。

所以問題是哪一個更好,unbox或使用InsertList<T>?哪一個更昂貴?

class MyClass 
{ 
} 

IList<MyClass> Method1() 
{ 
} 

class MainClass 
{ 
    List<MyClass> list = (List<MyClass>)Method1(); 
    list.insert(0,new MyClass{...}); //insert at the start. 

    Stack<MyClass> stack = (Stack<MyClass>)Method1(); 
    stack.Push(new MyClass{...}); //insert at the start 
} 
+4

['Stack'](http://msdn.microsoft.com/en-us/library/3278tedw.aspx)沒有實現'IList '接口,所以應該總是失敗。 –

+0

堆棧沒有實現IList ,所以這整個問題是沒有意義的。 IList 說:「我的行爲像一個列表,所以如果你願意,可以通過索引隨時訪問我。」堆棧說:「我是一個堆棧,只能從頂部訪問我*。」有點問題,不是嗎? – dlev

+0

我很抱歉,我沒有運行代碼,但它編譯並編寫了SO.My Bad的問題。 –

回答

3

你這裏不是拆箱在任一版本(雖然第一個將無法編譯..和第二總是在運行時失敗) -

然而,在這兩種情況下,如果你做的轉換,它只有在實際的底層實現是時纔會起作用。

如果您的方法返回IList<T>,我強烈建議堅持IList<T>成員。將結果轉換爲List<T>Stack<T>(即:無論內部實現是什麼 - 不是Stack<T>,因爲它沒有實現IList<T>)是非常危險的。

返回IList<T>的主要原因是有意讓您稍後更改內部實現。在內部,Method1可能稍後會從List<T>更改爲其他IList<T>,這會導致您的代碼意外中斷。這就是說,如果你知道內部實現可能是某種類型,你可以檢查它 - 但我不會盲目施放。

+0

我已經刪除了我的答案,它建議將測試轉換爲堆棧這是不可能的,因爲堆棧沒有實現IList '。你的強烈建議實際上是一項要求:) – user7116

+0

@sixlettervariables:是的,我知道 - 我還提到了一個編輯 - 我認爲這是一個例子,因爲在原始問題中**既不**也不編譯;) –

1

List<T>中插入一個值要比在Stack<T>中推送一個值要慢。

,對於在列表中插入從推到堆棧中的不同操作的原因。當您將新項目插入列表的中間時,之後的整個數組必須移位一個。這是一個O(n)操作。推入堆棧只是將值添加到內部數組的末尾。這很便宜 - O(1)。可比較的操作是List<T>.Add

但我認爲這裏有一個誤解,何時使用哪個。對於相同的操作,在實現方式或性能方面,List<T>Stack<T>之間沒有區別。唯一的區別在於每個集合公開的特徵。你可以模仿彈出Stack<T>List<T>(添加到列表的末尾,並從末尾刪除:list.RemoveAt(list.Count - 1))。這就是你想要在這裏使用它的方式。如果您打算使用List<T>作爲Stack<T>,則丟棄前者並始終使用後者。它使你的意圖更清晰。因此,您未來不太容易出錯。

但是要使用堆棧,我需要取消它。

這裏沒有拆箱。拆箱時,您從參考類型(object,IList<T>)轉換爲值類型(如結構,枚舉)。 Stack<T>不是一個值類型,因此沒有拆箱。它只是參考轉換,保存身份。它的價格很便宜。

所以,問題是哪一個更好,拆箱或使用List<T>Insert?哪一個更昂貴?

  • 你的第二個代碼不起作用。 Stack<T>不是IList<T>。所以你只剩下一個選擇。

  • Insert絕對是昂貴的,但這並不意味着你應該使用Stack<T>Stack<T>不會給你通過索引隨機訪問,從中間刪除等,但如果你只需要一個Stack<T>,堅持下去。 List<T>太籠統,你可以做很多事情。

底線:你要麼返回Stack<T>,並使用它(更好的性能),或返回IList<T>並使用它(更多功能)。最後,首先根據使用情況決定。