变量引用同一个实例

Variables refer to the same instance

在我的学习曲线中,我尝试在 ListIEnumerable 之间相互转换。

令我惊讶的是,在执行 EditMyList 过程后,MyIEnumerable 包含与 MyList 每个 DBTable 对象相同的数据。但是,我只修改了 MyList,一旦修改了 List,就没有将其分配给 MyIEnumerable

你能解释一下这里发生了什么吗?为什么 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

更新:string 最后 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"

A List 是引用类型。这意味着它是在堆上创建的,并且您的 MyList 变量仅包含对列表的引用(有时错误地称为 "pointer")。当您将 MyList 分配给 MyEnumerable 时,您不会复制整个列表,而只是复制引用。这意味着您对(一个)列表所做的所有更改都会反映在所有引用中。

如果您想要一个新列表,则需要创建它。您可以使用 the list constructor:

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

因为你不需要一个列表,而是一个 IEnumerable 你也可以调用列表的 ToArray 方法:

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

您也可以使用 LINQ:

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

String 的行为而言,.net 中的字符串是 不可变的 。这意味着它们一旦创建就无法更改。字符串操作(例如连接)总是会创建新的字符串。换句话说:您必须为列表手动执行的复制操作对于字符串会自动完成。这就是为什么您会看到字符串的行为与值类型的行为相似。

此外,如果字符串是可变的,您问题中的赋值操作也将表现相同。当您分配 a = "xxx" 时,您将 a 的引用从 "bbb" 更新为 "xxx"。然而,这不会影响 b,它仍然保留其旧引用。

使用 ToList() 扩展方法创建另一个 List

Dim newCollection = MyList.ToList()

但请注意 DBTable 的实例仍将引用相同的项目

要创建 "full" 副本,您需要为集合中的每个项目创建 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