这个在VB.Net中清除的对象列表(arrayLists)是什么?

时间:2011-07-12 19:53:22

标签: .net 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

然后我有一个代码块,当我按下一个按钮将一个新的testListClass对象传递给包含三个值(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

在“theList.Add(New testListClass(localArrayList))”调用之后,该List包含一个“testListClass”对象,它包含三个值(1,2,3),就像我期望的那样。以下是我不明白的。下一个电话是:

localArrayList.Clear()  

如果我在调试器中设置断点并执行此行,我看到的是:

列表(0).classArrayList现已被清除。在clear()之前它包含三个值(1,2,3),在调用清除本地定义的arrayList之后,“theList(0)”的内容现在已被清除。这是为什么?我认为,因为New constructor参数是通过值(ByVal)传递的,所以在调用代码中本地更改容器值对先前传递给不同类中的另一个方法的值没有影响。我在这里错过了什么明显的校长?

5 个答案:

答案 0 :(得分:3)

它是通过值传递的,但ArrayList(与所有类一样)是引用类型。所以你通过值传递引用。除非对象本身提供了一种方法,否则.NET永远不会为您复制对象。

在这种情况下,您可能希望使用ArrayList.Clone()方法。

答案 1 :(得分:1)

据我所知,byval意味着将实际的新对象分配给提供的byval参数不会更新callee方法中的引用。但是,你仍然可以通过访问它的属性等来访问和更改它的内部值,因为它仍然是一个对象。

即。如果你这样做了

suppliedList = new List();

它不会重置被调用方法的列表。但如果你这样做了。

suppliedList.Clear()

它会。

答案 2 :(得分:1)

<。> .Net中的ByVal并不代表您的想法。

ArrayList是引用类型。传递引用类型ByVal时,引用本身的值将传递给函数。函数中的变量和调用站点中的变量仍然引用内存中的同一对象,因此从调用站点调用.Clear()将清除添加到testList中的对象。

这与传递对象ByRef之间的区别是如果在函数内的对象上使用赋值,会发​​生什么。如果传递ByRef,则直接对函数中的变量进行的赋值也会影响调用站点。如果您通过ByVal,这些分配将不会影响呼叫站点。

如果你试图强制它克隆你的列表,那么就没有真正的内置支持。您可以使用.ToList()扩展方法使用值类型伪造它,但这只是方法的副作用,对于引用类型,您有一个相同对象的列表。对于其他类型,您通常可以使用.Net的序列化功能来克隆对象。但大多数时候,最简单,最可靠的方法就是手工完成。

答案 3 :(得分:0)

问题是'localArrayList'是一个指向列表的指针,因为它保存在内存中。当您使用该列表执行其他操作时,例如将其添加到类或列表中,您只需要指向相同的内存空间,因此执行localArrayList.Clear()只需清除所有指针的内存空间中的实例。

相反,您应该再次执行Dim localArrayList As New ArrayList(),而不是执行清除的行。这将启动列表的新实例,并保留旧的实例。

另外,BYVal并没有产生很大的差别,因为你传递的对象不是值类型(例如整数)它是引用类型(即对象) - 正如我之前所说,你将引用传递给列表,而不是列表。

有关详情,请参阅以下问题:ByRef vs ByVal Clarification

答案 4 :(得分:0)

写作: classArrayList = theList

您指定,从现在开始(直到更改) classArrayList TheList 位于相同的物理内存位置。改变一个你改变另一个。