Сохранение назначений в объекте, переданном по ссылке

Я хотел бы подтвердить расширение некоторых вещей, которые я пытался понять.

У меня есть два сценария:

Сценарий 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()
Другие вопросы по тегам