2017-01-04 6 views
0

私の学習曲線の中で私はListIEnumerableをお互いに変換して遊んでいます。私はと驚いて何変数は同じインスタンスを参照

EditMyList手順MyIEnumerableを実行した後MyListとして各DBTableオブジェクトに対して同じデータが含まれていることです。しかし、私はMyIEnumerableListが一度変更されていない限り、MyListのみを変更しました。

ここで何が起こったのか、またMyListMyEInumerableが同じインスタンスを参照する理由を説明できますか?

Public Class DBTable 
    Public Property TableName As String 
    Public Property NumberOfRows As Integer 
End Class 

Public Sub EditMyList 
    Dim MyList As New List(Of DBTable) 
    MyList.Add(New DBTable With {.TableName = "A", .NumberOfRows = 1}) 
    MyList.Add(New DBTable With {.TableName = "B", .NumberOfRows = 2}) 
    MyList.Add(New DBTable With {.TableName = "C", .NumberOfRows = 3}) 

    Dim MyIEnumerable As IEnumerable(Of DBTable) = MyList 

    For Each item In MyList 
     item.NumberOfRows += 10 
    Next 
End Sub 

更新日:ケース終了bがaと等しくない場合。 Stringも参照型であるため、ある変数を他の変数に代入すると、参照のみがコピーされます。しかしながら、端部に第一の例とは異なる結果が(@Sefeにより説明)ある

Dim a As String 
Dim b As String 
a = "aaa" 
b = "bbb" 
a = b 
' At this point a and b have the same value of "bbb" 
a = "xxx" 
' At this point I would expect a and b equal to "xxx", however a="xxx" but b="bbb" 
+0

ここでは何が起こったのですか? MyListとMyIEnumerableは両方とも同じインスタンスを参照するため、リストは1つだけですが、参照は2つです。それはなぜ起こったのですか?参照を割り当てたので、 'Dim MyIEnumerable As IEnumerable(Of DBTable)= MyList'です。 –

答えて

1

List参照型です。これは、ヒープ上に作成され、MyList変数にリストへの参照(誤って「ポインタ」と呼ばれることがある)だけが含まれていることを意味します。 MyListMyEnumerableに割り当てると、リスト全体がコピーされません。参照をコピーするだけです。つまり、(1つの)リストに加えたすべての変更は、すべての参照に反映されます。

新しいリストを作成する場合は、作成する必要があります。あなたがリストを必要としないので

Dim MyIEnumerable As IEnumerable(Of DBTable) = New List(Of DBTable)(MyList) 

が、あなたはまた、リストのToArrayメソッドを呼び出すことができIEnumerable:あなたはthe list constructorを使用することができます。また、LINQを使用することができます

Dim MyIEnumerable As IEnumerable(Of DBTable) = MyList.ToArray 

を:

Dim MyIEnumerable As IEnumerable(Of DBTable) = MyList.ToList 

Stringの動作に関する限り、.netの文字列はであり、変更不可能なのはです。つまり、一度作成されると、変更することはできません。文字列操作(例えば、連結)は、常に新しい文字列を作成します。言い換えると、リストのために手動で行う必要があるコピー操作は、文字列に対して自動的に行われます。そのため、値型の場合と同じような文字列の動作が見られます。

また、文字列が変更可能であれば、あなたの質問の割り当て操作も同じように動作します。 a = "xxx"を割り当てると、から"xxx"への参照をaに更新します。ただし、bには影響はありません。bは古い参照を保持します。別のList

Dim newCollection = MyList.ToList() 

しかしを作成するための

+0

次に、別のインスタンスを取得するために、MyListをMyEnumerableにどのように割り当てる必要がありますか? – Megrez7

+1

新しいリストを作成し、あるリストから別のリストに要素をコピーする必要があります。私の編集をチェックしてください。 – Sefe

+0

事がより明確になります。しかし、なぜ2つの 'string'変数(参照型も)の場合、それはなぜ異なって動作しますか?私の更新を参照してください。 – Megrez7

1

使用ToList()拡張メソッドがDBTableのインスタンスがまだ「フル」を作成するために、同じアイテム

に参照することに気づくあなたがDBTableの新しいインスタンスを作成する必要がありますコピーコレクションのすべてのアイテム

Dim newCollection = MyList.Select(Function(item) 
             return new DBTable 
             { 
              .TableName = item.TableName, 
              .NumberOfRows = item.NumberOfRows 
             } 
            End Function).ToList() 


For Each item in MyList 
    item.NumberOfrows += 10 ' will not affect on the newCollection items 
Next 
+0

これは問題を解決しません。なぜなら、 '選択 'は既存のリストで機能するからです。リスト内の項目を変更すると、選択項目に反映されます。 – Sefe

+0

'Select'は、OPが列挙できる新しいIEnumerableを作成するように頼みます。 – Fabio

+1

いいえ、彼は元の列挙型と変わらない列挙型を望んでいます。古いリストは既に列挙できます。 – Sefe

関連する問題