Мне несколько непонятны ссылки (указатели?) На классы в VB.NET. На вопрос, который я собираюсь задать, можно ответить, проведя небольшое тестирование, но мне было интересно, может ли кто-нибудь опубликовать достойное объяснение (или ссылки тоже).
Если вы создаете класс:
Public Class ReferenceClass
Private myBooleanValue As Boolean = False
Public Property BooleanValue As Boolean
Get
Return myBooleanValue
End Get
Set(value As Boolean)
myBooleanValue = value
End Set
End Property
End Class
А затем класс, который фактически использует этот класс как свойство:
Public Class UsingClass
Private myReference As ReferenceClass
Public Property Reference As ReferenceClass
Get
return myReference
End Get
Set(value As ReferenceClass)
myReference = value
End Set
End Property
Public Sub New(ByVal Reference As ReferenceClass)
myReference = Reference
End Sub
End Class
А затем используйте это так:
Public Class RuntimeOrSomething
Public Shared myReference As ReferenceClass
Public Shared ReadOnly Property Reference As ReferenceClass
Get
If myReference Is Nothing Then myReference = new ReferenceClass()
return myReference
End Get
End Property
Public Shared Function BooleanCheck() As Boolean
Reference.BooleanValue = True
Dim tempClass As New UsingClass(Reference)
tempClass.Reference.BooleanValue = False
Return (tempClass.Reference.BooleanValue = Reference.BooleanValue)
End Sub
Public Shared Sub DoNothing()
Reference.BooleanValue = True
Dim someBoolean As Boolean = BooleanCheck
' Now Reference.Booleanvalue is "False"
End Sub
End Class
Теперь функция BooleanCheck всегда будет возвращать true, даже если ссылка передается в новый класс UsingClass «по значению», а не по ссылке. Таким образом, копия класса не создается, но локальная переменная myReference в UsingClass по-прежнему ссылается / указывает на свойство Reference в RuntimeOrSomething.
Как это можно элегантно объяснить?





Я не могу сейчас уделить много времени этому ответу - печатать в поезде с малышом на коленях - но у меня есть пара статей, которые могут помочь. Они написаны о C#, но то же самое относится и к VB.NET:
спасибо, хорошие статьи, которые теперь в моем "списке для чтения" :-)
Ссылка указывает на экземпляр объекта, это не экземпляр объекта. Создание копии указаний к объекту не создает другой объект, а создает еще одну ссылку, которая также указывает на тот же объект.
спасибо, вы были первым с простым и понятным объяснением.
Есть любопытное исключение из этого принципа: если рассматриваемая ссылка указывает на упакованный непримитивный тип значения, и если тип источника и тип назначения назначения - Object, то по какой-то причине VB.NET сохранит ссылку на копия объекта, а не оригинал.
В этой строке:
Dim tempClass as New UsingClass(Reference)
объект, на который ссылается свойство Reference, передается «по значению», но копируется не объект, это Справка к этому объекту, который копируется (т.е. myReference и tempClass.Reference - это два разных «указателя» на один и тот же объект. Затем вы можете сделать tempClass.Reference = new ReferenceClass, а затем myReference и tempClass.Reference по-прежнему являются двумя разными «указателями», но теперь каждый из них указывает на два разных объекта.
При передаче классов byval / byref в VB.NET можно думать об этом с точки зрения программирования на C и указателей таким образом, что -
ByVal = passing arguments via - a pointer ByRef = passing arguments via - a pointer to a pointer
Возьмем для примера струны
' ByRef - modify str pointer to "point" to a new string
Sub Test_Ref(ByRef str as string)
str = "New String ByRef"
End Sub
' ByVal - can't modify str pointer must return a (pointer to) new string
Function Test_Val(ByVal str as String) as String
Return "New String ByVal"
End Sub
Sub Main()
Dim strTest as String = "Hello World!"
Console.WriteLine(strTest)
Test_Ref(strTest)
Console.WriteLine(strTest)
Test_Val(strTest)
Console.WriteLine(strTest) ' oops still pointing to same string
strTest = Test_Val(strTest)
Console.WriteLine(strTest) ' that's better :)
End Sub
От MSDN:
If you pass a variable argument by value using the ByVal keyword, the procedure cannot modify the variable itself. However, if the argument is a reference type, you can modify the members of the object to which it points, even though you cannot replace the object itself. In particular, you can modify the members of the object. For example, if the argument is an array variable, you cannot assign a new array to it, but you can change one or more of its elements. The changed elements are reflected in the underlying array variable in the calling code.
Поскольку ваш ReferenceClass является ссылочным типом, если вы передадите его ByVal, вы не сможете заменить его новым объектом (чего у вас нет), но вы можете возиться с его внутренностями (что вы и делаете). Независимо от того, передаете ли вы ByRef или ByVal, работа с его внутренностями все равно "повлияет" на исходный объект (поскольку в памяти всегда есть только один объект).
спасибо за ссылку msdn, я как-то полностью пропустил это во время предыдущих посещений и поисков там
Как сказано выше, установка объектной переменной, равной другой, просто устанавливает «указатель» на экземпляр того же объекта в памяти, если вы хотите клонировать объект, посмотрите на реализацию интерфейса iCloneable с чем-то вроде
Public Function Clone() As Object Implements ICloneable.Clone
Return Me.MemberwiseClone()
End Function
С и при выделении объекта используйте метод клонирования
Dim tempClass as ReferenceClass = Reference.Clone
О, мистер Скит, я считаю, что вы ДЕЙСТВИТЕЛЬНО пристрастились к SOFlow с таким ответом прямо здесь. 8 ^ D