What is this list of objects (arrayLists) being cleared in VB.Net?
Sorry for such a basic scoping question but I am obviously not understanding something about scoping that is very basic. I have a very simple class:
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
Then I have a block of code that instantiates this when I press a button passing a new testListClass object to it containing three values (1,2,3).
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
After the "theList.Add(New testListClass(localArrayList))" call, theList contains one "testListClass" object which contains three values (1,2,3) just as I would expect. The following is the what I don't understand. The next call is:
localArrayList.Clear()
If I set a breakpoint here in the debugger and execute this line what I see is:
theList(0).classArrayList has now been cleared. Where before the clear() it contained three values (1,2,3), after the call to clear the locally defined arrayList, the contents of "theList(0)" have now been cleared. Why is that? I would think since the New constructor parameter is passed by value (ByVal)开发者_运维问答, locally changing a container value in the calling code would have no effect on the values previously passed to another method in a different class. What obvious principal am I missing here?
It's passed by value, but ArrayList (like all classes) is a reference type. So you are passing the reference by value. .NET will never copy objects for you unless the object itself provides a way to do that.
In this case you might want to use the ArrayList.Clone() method.
As far as I am aware byval means that assigning an actual new object to the supplied byval parameter would not update the reference in the callee method. However you can still access and change it's internal values by accessing it's propertys etc as it is still an object.
i.e. if you did this
suppliedList = new List();
it would not reset the list of the callee method. but if you did this.
suppliedList.Clear()
it would.
ByVal in .Net doesn't mean what you think it does.
ArrayList is a reference type. When you pass a reference type ByVal, the value of the reference itself is passed to the function. The variable in the function and the variable from the call site still refer to the same object in memory, and so calling .Clear() from the call site will clear the object you added to your testList.
The difference between this and passing the object ByRef is what happens if you use assignment on the object within the function. If you pass ByRef, assignments made directly to the variable within a function will also effect a call site. If you pass ByVal, these assignments will not effect the call site.
If you're trying to force it to clone your list, there's no real built-in support for this. You can fake it with value types by using the .ToList()
extension method, but that's just a side-effect of the method and for reference types you have a list of the same objects. For other types, you can often use .Net's serialization features to clone objects. But most of the time, the easiest and most reliable way to accomplish this is to do it by hand.
The problem is that 'localArrayList' is a pointer to the list as it is held in memory. When you do other things with that list, such as add it to classes or lists, you're just making more pointers to the same memory space, so doing localArrayList.Clear()
just clears the instance in that memory space for all pointers.
Instead you should do Dim localArrayList As New ArrayList()
again instead of the line where you do a clear. This will start a new instance of the list and leave the old one alone.
In addition, BYVal doesn't make a whole lot of difference as the object you are passing is not a value type (such as an integer) it is a reference type (ie an object) - as I said before, you are passing the reference to the list, not the list.
See the following question for more: ByRef vs ByVal Clarification
by writing: classArrayList = theList
you specify, that from now on (until changed) classArrayList and TheList are in the same physical memory locations. Change one and you change the other.
精彩评论