2011-07-12 4 views
2

このような基本的なスコープの質問は申し訳ありませんが、私は明らかに非常に基本的なスコープについて何かを理解していません。私は非常に単純なクラスを持っている:VB.Netでこのオブジェクト(配列リスト)の一覧を消去していますか?

Public Class testListClass 
    ' This just contains a single list that is set by a property or the constructor 
    Private classArrayList As New ArrayList() 

    Public Sub New(ByVal theList As ArrayList) 
     classArrayList = theList 
    End Sub 
End Class 

私はそれが3つの値(1,2,3)を含む新しいtestListClassオブジェクトを渡すボタンを押すと、それから私はこれをインスタンス化するコードのブロックを持っています。 "theList.Add(新testListClass(localArrayList))" コールの後

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click 
    ' Lets see if changing the arrayList results in all of the testListClass items being changed 
    Dim theList As New List(Of testListClass) 
    Dim localArrayList As New ArrayList() 

    localArrayList.Add(1) 
    localArrayList.Add(2) 
    localArrayList.Add(3) 

    theList.Add(New testListClass(localArrayList)) 

    ' This results in theList.classArrayList being cleared. Why since the parameter 
    ' to the constructor is passed by value? 
    localArrayList.Clear() 

    localArrayList.Add(10) 
    localArrayList.Add(20) 

    theList.Add(New testListClass(localArrayList)) 


End Sub 

、theListは1、私が期待するのと同じように3つの値(1,2,3)を含む "testListClass" オブジェクトが含まれています。以下は私が理解していないものです。次の呼び出しは次のとおりです。

localArrayList.Clear() 

私はここに、デバッガでブレークポイントを設定し、私が何を参照してください。この行を実行した場合である:.classArrayListは今クリアされた

theList(0)。 clear()の前に3つの値(1,2,3)が含まれていたところで、ローカル定義のarrayListをクリアする呼び出しの後、 "theList(0)"の内容はクリアされました。何故ですか?私は、新しいコンストラクタのパラメータが値(ByVal)によって渡されるので、呼び出し元のコードのコンテナ値をローカルに変更すると、以前に別のクラスの別のメソッドに渡された値に影響しないと思います。私はここで何が分かりますか?

+0

タイトルが残念です...「なぜ」ではなく、「何」であったはずです。これを再生した後、リストをクローンすると正しく動作するように見えます。したがって、 "theList.Add(new testListClass(localArrayList))"を "theList.Add(New testListClass(localArrayList.clone))"に変更すると、動作します。 – GregH

+1

'List 'の代わりに 'ArrayList'を使っている理由はありますか?それが 'List 'であったとしても、それは汎用コレクションインタフェースを実装しているので、 'ArrayList'よりも優れています。 – CodesInChaos

答えて

3

これは値で渡されたのが、ArrayListには(すべてのクラスのような)参照型です。だからあなたは値で参照を渡しています。オブジェクト自体がその方法を提供しない限り、.NETはあなたのためにオブジェクトをコピーしません。

この場合、ArrayList.Clone()メソッドを使用できます。

1

私が知っている限り、実際の新しいオブジェクトを指定されたbyvalパラメータに割り当てると、呼び出し先メソッドの参照は更新されません。しかし、依然としてオブジェクトであるため、プロパティなどにアクセスすることによって、内部値にアクセスして変更することができます。あなたはこの

suppliedList = new List(); 

をしなかった場合

すなわち、それは、呼び出し先メソッドのリストをリセットしません。しかしもしあなたがこれをしたら。

suppliedList.Clear() 

です。

0

'localArrayList'は、メモリ内に保持されているリストへのポインタです。クラスやリストに追加するなど、そのリストで他のことを行うときは、同じメモリ空間へのポインタを増やすだけです。したがって、localArrayList.Clear()を実行すると、すべてのポインタのメモリ空間のインスタンスが消去されます。

代わりに、クリアする行の代わりにDim localArrayList As New ArrayList()を再度入力する必要があります。これは、リストの新しいインスタンスを開始し、古いものだけを残します。

さらに、BYValは、渡すオブジェクトが参照型(オブジェクトなど)である値型(つまり、整数など)ではないため、大きな違いはありません。リストを参照するのではなく、リストに参照を渡しています。

は、より多くのために、次の質問を参照してください。ByRef vs ByVal Clarification

1

ByVal。ネットはあなたが思うものを意味するものではありません。

ArrayListは参照型です。参照型ByValを渡すと、参照自体の値が関数に渡されます。関数内の変数とコールサイトの変数は、メモリ内の同じオブジェクトを参照しているため、コールサイトから.Clear()を呼び出すと、testListに追加したオブジェクトがクリアされます。

これとオブジェクトByRefを渡すことの違いは、関数内のオブジェクトに対して代入を使用するとどうなりますか。 ByRefを渡すと、関数内の変数に直接代入された代入もコールサイトに影響します。 ByValを渡すと、これらの割り当てはコールサイトには影響しません。

強制的にリストを複製しようとしている場合は、実際の組み込みサポートはありません。 .ToList()拡張メソッドを使用して値の種類を偽装することはできますが、これはメソッドの副作用に過ぎず、参照型にはの同じオブジェクトのリストがあります。他のタイプの場合、.Netのシリアル化機能を使用してオブジェクトを複製することができます。しかし、ほとんどの場合、これを達成する最も簡単で信頼できる方法は手作業で行うことです。書き込みによる

0

classArrayList = theList

、指定し、その今からclassArrayList(変更まで)TheListが同じ物理メモリ位置にあります。 1つを変更し、もう一方を変更します。

関連する問題