变量引用同一个实例
Variables refer to the same instance
在我的学习曲线中,我尝试在 List
和 IEnumerable
之间相互转换。
令我惊讶的是,在执行 EditMyList
过程后,MyIEnumerable
包含与 MyList
每个 DBTable
对象相同的数据。但是,我只修改了 MyList
,一旦修改了 List
,就没有将其分配给 MyIEnumerable
。
你能解释一下这里发生了什么吗?为什么 MyList
和 MyEInumerable
指的是同一个实例?
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
在我的学习曲线中,我尝试在 List
和 IEnumerable
之间相互转换。
令我惊讶的是,在执行 EditMyList
过程后,MyIEnumerable
包含与 MyList
每个 DBTable
对象相同的数据。但是,我只修改了 MyList
,一旦修改了 List
,就没有将其分配给 MyIEnumerable
。
你能解释一下这里发生了什么吗?为什么 MyList
和 MyEInumerable
指的是同一个实例?
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