Сохранение назначений в объекте, переданном по ссылке
Я хотел бы подтвердить расширение некоторых вещей, которые я пытался понять.
У меня есть два сценария:
Сценарий 1: у меня один список хранится в приватном поле моего класса, я делаю его полную копию и сохраняю в другом приватном поле. После этого я делаю некоторые изменения в списке, но я могу выбрать восстановление его исходного состояния. Для этого я назначаю копию исходного списка измененному:
Public Class ClassX
Private myList As List(Of Double)
Private myOriginalList As List(Of Double)
Public Sub New()
myList = New List(Of Double)
myOriginalList = ObjectCopier.Clone(myList)
End Sub
Private Sub Main()
ChangeMyList()
'myList has one element
RevertChanges()
'myList has zero elements
End Sub
Public Sub ChangeMyList()
Dim r As New Random
myList.Add(r.NextDouble)
End Sub
Public Sub RevertChanges()
myList = myOriginalList
End Sub
End Class
Делая так, заставляет все работать так, как я ожидал.
Сценарий 2: Идея почти такая же, сделайте глубокую копию одного списка, чтобы можно было восстановить его исходное состояние. Однако в этом случае список передается другому объекту, который делает его полную копию, изменяет его и решает сохранить эти изменения или отменить их. При этом я не могу получить желаемое поведение, так как список меняется, даже когда я делаю присваивание "myList = myOriginalList". Код:
Public Class ClassX
Private myList As List(Of Double)
Private Sub Main()
Dim myList As New List(Of Double)
Dim c As New ClassY(myList)
c.ChangeList()
'myList has one element
c.RevertChanges()
'myList still has one element
End Sub
End Class
Public Class ClassY
Private myList As List(Of Double)
Private myOriginalList As List(Of Double)
Public Sub New(ByVal c As List(Of Double))
myList = c
myOriginalList = ObjectCopier.Clone(myList)
End Sub
Public Sub ChangeList()
Dim r As New Random
myList.Add(r.NextDouble)
End Sub
Public Sub RevertChanges()
myList = myOriginalList
End Sub
End Class
Итак, вопрос... почему? Почему я могу отменить изменения таким способом в первом случае, а не во втором? Почему изменения, внесенные в список, переданный как ссылка на ClassY, сохраняются, но назначение не передается в исходный список в ClassX?
Надеюсь, это имеет смысл! Спасибо!
2 ответа
Установка "myList" в ClassY обратно на оригинал не меняет "myList" в методе "Main". Пусть 'RevertChanges' принимает параметр списка:
Public Sub RevertChanges(ByRef changedList As List(Of Double))
myList = myOriginalList
changedList = myList
End Sub
Я адаптировал ваш код, чтобы избежать использования того же имени переменной, что иc
.
Я также реализовалObjectCopier()
чтобы код VB.Net можно было протестировать для других читателей.
Используя следующий код
Module MainModule
Public Class ObjectCopier
Public Shared Function Clone(ByRef lst As List(Of Double)) As List(Of Double)
Return lst.AsEnumerable().ToList()
End Function
End Class
Private myList As List(Of Double)
Public Sub Main()
Dim myList As New List(Of Double)
Dim c As New ClassY(myList)
Console.WriteLine(">> mylist.Count(): " & CStr(myList.Count()))
Console.WriteLine(">> c.myClasslist.Count(): " & CStr(c.myClassList.Count()))
Console.WriteLine(">> c.myOriginalList.Count(): " & CStr(c.myOriginalList.Count()))
c.ChangeList()
Console.WriteLine(">> mylist.Count(): " & CStr(myList.Count()))
Console.WriteLine(">> c.myClasslist.Count(): " & CStr(c.myClassList.Count()))
Console.WriteLine(">> c.myOriginalList.Count(): " & CStr(c.myOriginalList.Count()))
c.RevertChanges()
Console.WriteLine(">> mylist.Count(): " & CStr(myList.Count()))
Console.WriteLine(">> c.myClasslist.Count(): " & CStr(c.myClassList.Count()))
Console.WriteLine(">> c.myOriginalList.Count(): " & CStr(c.myOriginalList.Count()))
End Sub
Public Class ClassY
Public myClassList As List(Of Double)
Public myOriginalList As List(Of Double)
Public Sub New(ByVal lst As List(Of Double))
myClassList = lst
myOriginalList = ObjectCopier.Clone(myClassList)
End Sub
Public Sub ChangeList()
myClassList.Add(1.0)
End Sub
Public Sub RevertChanges()
myClassList = myOriginalList
End Sub
End Class
End Module
Я получаю следующий результат
>> mylist.Count(): 0
>> c.myClasslist.Count(): 0
>> c.myOriginalList.Count(): 0
>> mylist.Count(): 1
>> c.myClasslist.Count(): 1
>> c.myOriginalList.Count(): 0
>> mylist.Count(): 1
>> c.myClasslist.Count(): 0
>> c.myOriginalList.Count(): 0
Как видите, толькоc.myClassList.Count()
изменяется с 1 на 0 в функции.
Почему ? Потому что перед вызовом функции
myList point to Address-X1
myClassList point to Address-X1
myOriginalList point to Address-X3
и после
myList continue to point to Address-X1
myClassList point to Address-X3
myOriginalList point to Address-X3
Внимание: если сейчас вы добавите новый элемент в переменную, вы изменится, потому что вам придется клонировать myOriginalList
восстановить исходное значение в !!!
Чтобы изменить , вы должны передать его по ссылке вRevertChanges()
функция.
Public Sub RevertChanges(ByRef lst As List(Of Double))
myClassList = myOriginalList
lst = myOriginalList
End Sub
или вернуть новыйmyClassList
из функции RevertChanges() и назначьте ееmyList
.
Public Function RevertChanges() as List(Of Double)
myClassList = myOriginalList
return MyClassList
End Function
myList = c.RevertChanges()