2016-05-16 26 views
0

爲什麼要將值分配給List必須使用Add完成,但是可以使用[]運算符完成對數組的操作?將值分配給列表與數組以及ArgumentOutOfRangeException

例如:

string[] y = new string[10]; 
    y[0] = "asdf"; //fine 

    List<string> x = new List<string>(10); 
    x[0] = "asdf"; //ArgumentOutOfRangeException 

不應該具有相同的行爲呢?

+0

'不應該都具有相同的行爲嗎?不。爲什麼它應該是相同的?它們不是同一個東西... – Eser

+0

您需要先將字符串「asdf」添加到x,然後才能使用它。 x.add( 「ASDF」)。現在列表是空的。 – Auguste

+0

爲什麼你會認爲他們會有相同的行爲?列表和數組是不同的東西。 – itsme86

回答

4

考慮看看的源代碼清單(T)的,你看到的索引屬性的getter/setter方法是這樣的:

// Sets or Gets the element at the given index. 
    // 
    public T this[int index] { 
     get { 
      // Fllowing trick can reduce the range check by one 
      if ((uint) index >= (uint)_size) { 
       ThrowHelper.ThrowArgumentOutOfRangeException(); 
      } 
      return _items[index]; 
     } 
     set { 
      if ((uint) index >= (uint)_size) { 
       ThrowHelper.ThrowArgumentOutOfRangeException(); 
      } 
      _items[index] = value; 
      _version++; 
     } 
    } 

注意,之前設置在列表內部的相應項目數組,它首先檢查私人_size變量以確保它在範圍內。但是,_size未設置爲陣列的大小。大小在列表的各種添加/刪除方法中增加/減少,因此即使您初始化一個初始容量爲10的列表,即列表數組的容量爲內部。下面是構造函數:

// Constructs a List with a given initial capacity. The list is 
    // initially empty, but will have room for the given number of elements 
    // before any reallocations are required. 
    // 
    public List(int capacity) { 
     if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_SmallCapacity); 
     _items = new T[capacity]; 
    } 

_size沒有設置(並因此保持爲0的初始值),除非您使用添加/刪除/的AddRange /等。或者使用接受IEnumerable的構造函數(在這種情況下,因爲IEnumerable中的項數)。

如果你仔細想想,這是有道理的。列表的想法是,您不必擔心數字索引的複雜性(和醜陋),並在容量需要更改時調整/複製數組。在實例化List之後,內部數組的大小應該與開發人員無關。如果您想微觀管理內部數組的使用方式,那麼您應該創建自己的實現,或者只使用一個數組。

-2

此構造函數不會在列表中創建任何元素。它只是爲可添加到此列表的項目預留內存。 您仍然需要手動插入項目到列表中,然後才能以此方式使用。

更新: 這個重載可以幫助你,當你處理大集合,你幾乎可以確定你會把約N個項目放入你的列表中。因此,您可以在創建時保留內存,並避免在向此列表中添加項目時進行內存分配(有時可能會很慢)。

+0

儘管如此,這並不能真正解決問題。問題是爲什麼,如果一個列表是以特定的容量創建的,那麼這個容量就不能被訪問。初始化容量爲10的數組實際上並沒有爲數組添加任何內容,但是在創建數組後,您仍然可以明確地指定每個元素。 – DVK

1

列表的內部結構與array不同。在array中,您的定義中包含大小的項目,因此需要使這些對象在內存中由CLR實時存儲。

list<T>中,您可以定義列表中項目的最大值。那是(的一部分,)你必須調用Add方法在list<T>中添加對象的原因。您可以像在構造函數中那樣爲列表定義初始Capacity。如果您需要添加超過容量,該列表將重新排列它。該框架爲您管理清單上有多少物品。

另一個重要的是,在這兩種情況下,您可以通過index訪問。對於樣本:

var obj = list[1]; 
var obj2 = array[1]; 

的情況下,你不必對list<T>/array1指數,在array,你得到的default(T)(考慮T爲你的類型),並在列表中你會得到一個Exception

+0

我喜歡這樣想的方式是當你初始化一個數組時你有一組方框。當你用一個size參數初始化一個列表時,你有一個可以容納一組框的倉庫(但是在你添加()它們之前沒有框) –

+0

謝謝@Steve,你是對的。我已經更新了我的答案。 –

+0

聲明「列表的內部結構與數組不同」,「但它不會在內存中實現」,這些陳述並不準確。一個列表,內部是一個數組。 List類只是它的一個包裝器,它處理調整大小,複製等。 – DVK

1

你實現你的數組的方式是正確的。

數組的大小需要在創建時聲明。這是沒有辦法的。

但是,列表的大小更加靈活。您可以添加儘可能多的元素,而無需聲明初始大小。但是,添加元素後,您可以通過索引號訪問或編輯它們。這是一個例子。

你會得到這個異常,因爲從技術上講,直到你真正給它添加一個值之前,列表並沒有填充索引。讓我知道如果它清除它。

//You can add your elements when you instantiate it 
    List<string> names = new List<string>{"Alex", "Tommy", "Bob"}; 

    //Or you can add them later 
    List<string> cities = new List<string>(); 

    cities.Add("Denver"); 
    cities.Add("New York"); 

    //Now that they are created you can access or edit any of the elements within them. 
    names[2] = "Gerard"; 
    cities[1] = "San Francisco";