2016-05-16 2 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

// 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は配列のサイズに設定されていません。 Sizeは、ListのさまざまなAdd/Removeメソッドで増減します。したがって、初期容量が10のリストをインスタンス化しても、リストの配列の内部の容量です。ここではコンストラクタがある:あなたが/ AddRangeの/ etcを追加/削除のいずれかを使用しない限り、

// 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が初期化された値のままとして)されていません。または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]; 

場合は、あなたがarrayで、list<T>/array1インデックスを持っていない、あなたが得るdefault(T)(あなたのタイプとしてTを考慮して)、リストにあなたが取得しますException。 、インデックス付きプロパティのゲッター/セッターはこのように見えることをご参照を(Tの)リストのソースコードを見てみると

+0

私はそれについて考えるのが好きなのは、あなたがボックスのグループを持っている配列を初期化するときです。サイズパラメータを持つリストを初期化すると、ボックス群を保持できる倉庫がありますが、追加するまでボックスはありません。 –

+0

ありがとうございます。私は私の答えを更新しました。 –

+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"; 
関連する問題