【问题标题】:What is this list of objects (arrayLists) being cleared in VB.Net?在 VB.Net 中清除的对象列表(arrayLists)是什么?
【发布时间】:2011-07-12 19:53:22
【问题描述】:

对于这样一个基本的范围界定问题,我很抱歉,但我显然不了解非常基本的范围界定。我有一个非常简单的课程:

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

然后我有一个代码块,当我按下一个按钮时,它会实例化它,将一个包含三个值 (1,2,3) 的新 testListClass 对象传递给它。

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))”调用之后,theList 包含一个“testListClass”对象,它包含三个值(1、2、3),正如我所期望的那样。以下是我不明白的。下一个电话是:

localArrayList.Clear()  

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

theList(0).classArrayList 现已被清除。在 clear() 之前它包含三个值 (1,2,3),在调用清除本地定义的 arrayList 之后,“theList(0)”的内容现在已被清除。这是为什么?我认为由于 New 构造函数参数是按值传递的 (ByVal),因此在调用代码中本地更改容器值不会影响先前传递给不同类中另一个方法的值。我在这里缺少什么明显的原则?

【问题讨论】:

  • 对不起标题...应该是“为什么”,而不是“什么”。在玩完这个之后,我注意到如果我克隆列表,它似乎可以正常工作。因此,如果我将“theList.Add(New testListClass(localArrayList))”更改为“theList.Add(New testListClass(localArrayList.clone))”,那么它可以工作。
  • 您使用ArrayList 而不是List<T> 有什么原因吗?即使它只是List<object>,它也比ArrayList 更可取,因为它实现了通用集合接口。

标签: .net vb.net


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    即如果你这样做了

    suppliedList = new List();
    

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

    suppliedList.Clear()
    

    会的。

    【讨论】:

      【解决方案3】:

      .Net 中的 ByVal 并不像您认为的那样。

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

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

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

      【讨论】:

        【解决方案4】:

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

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

        此外,BYVal 并没有太大的不同,因为您传递的对象不是值类型(例如整数)它是引用类型(即对象) - 正如我之前所说,您正在传递对列表的引用,而不是列表。

        请参阅以下问题了解更多信息:ByRef vs ByVal Clarification

        【讨论】:

          【解决方案5】:

          通过写作:classArrayList = theList

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

          【讨论】:

            猜你喜欢
            • 2013-08-21
            • 1970-01-01
            • 2018-04-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-03-04
            • 2013-03-22
            • 1970-01-01
            相关资源
            最近更新 更多