Diferença entre ByVal e ByRef?
-
29-10-2019 - |
Pergunta
Qual é a diferença?Sempre uso ByVal, mas não tenho uma boa ideia de quando devo e quando não ...
Solução
Se você passar uma referência, ao modificar o valor no método, a variável no site de chamada também será modificada.
Se você passar valor, é o mesmo que se outra variável fosse criada no método, então mesmo que você modifique, a variável original (no site da chamada) não terá seu valor alterado.
Então, de fato, você geralmente deve passar variáveis como valor.Passe como referência apenas se você tiver uma necessidade explícita de fazê-lo.
Outras dicas
ByRef= Você dá a seu amigo seu trabalho final (o original), ele o marca e pode devolvê-lo a você.
ByVal= Você deu a ele uma cópia do trabalho do termo e ele devolveu as alterações, mas você mesmo terá que colocá-las de volta no original.
O mais simples possível.
Por que usar Byref:
ByRef irá passar o PONTEIRO para o objeto que você está passando. Se você está no mesmo espaço de memória, isso significa passar apenas a 'palavra', não o objeto. O método para o qual você está passando pode fazer alterações no objeto original e não precisa passá-las de volta, pois estão no objeto original. Útil para agilizar a passagem de grandes volumes de dados. Você também pode usar ByRef para permitir o uso de um SUB em vez de uma FUNCTION (em VB), uma vez que não é necessário devolver o objeto.
Por que não usar o Byref:
Como o método tem acesso ao original, quaisquer alterações feitas serão imediatas e permanentes. Se o método falhar, o obleto pode ser corrompido. Usar ByVal fará uma cópia, passará a cópia inteira para o método, e então o método processará as informações e executará novamente uma cópia de volta, relatará as informações ou não fará nada.
Sei que essa pergunta já foi respondida, mas queria apenas acrescentar o seguinte ...
O objeto que você passa para uma função está sujeito a ByRef / ByVal, entretanto, se esse objeto contém referências a outros objetos, eles podem ser modificados pelo método chamado independentemente de ByRef / ByVal.Explicação ruim, eu sei, veja o código abaixo para um melhor entendimento:
Public Sub Test()
Dim testCase As List(Of String) = GetNewList()
ByRefChange1(testCase)
'testCase = Nothing
testCase = GetNewList()
ByValChange1(testCase)
'testCase is unchanged
testCase = GetNewList()
ByRefChange2(testCase)
'testCase contains the element "ByRef Change 2"
testCase = GetNewList()
ByValChange2(testCase)
'testCase contains the element "ByVal Change 2"
End Sub
Public Function GetNewList() As List(Of String)
Dim result As List(Of String) = New List(Of String)
result.Add("Value A")
result.Add("Value B")
result.Add("Value C")
Return result
End Function
Public Sub ByRefChange1(ByRef aList As List(Of String))
aList = Nothing
End Sub
Public Sub ByValChange1(ByVal aList As List(Of String))
aList = Nothing
End Sub
Public Sub ByRefChange2(ByRef aList As List(Of String))
aList.Add("ByRef Change 2")
End Sub
Public Sub ByValChange2(ByVal aList As List(Of String))
aList.Add("ByVal Change 2")
End Sub
EDITAR:
Além disso, considere se esta função foi chamada:
Public Sub ByValChange3(ByVal aList As List(Of String))
aList.Add("ByVal Change 3")
aList = New List(Of String)
aList.Add("ByVal Change 4")
End Sub
O que acontece neste caso é que "ByVal Change 3" é adicionado à lista de chamadores, mas no ponto em que você especifica que "aList= New List" você está apontando a nova referência, para um novo objeto, e se separada lista de chamadores.Tanto o bom senso quanto podem te pegar um dia, então algo para ter em mente.
Espero que isso responda à sua pergunta
Sub last_column_process()
Dim last_column As Integer
last_column = 234
MsgBox last_column
trying_byref x:=last_column
MsgBox last_column
trying_byval v:=last_column
MsgBox last_column
End Sub
Sub trying_byref(ByRef x)
x = 345
End Sub
Sub trying_byval(ByRef v)
v = 555
End Sub
Acho que pode ter ocorrido um erro de digitação na última amostra: O último sub deve ser "byval" e não "byref".:)
Também foi adicionada uma instrução msgbox em try_byval para que você possa entender o que significa.
Sub begin()
Dim last_column As Integer
last_column = 234
MsgBox "Begin:" & last_column
trying_byref x:=last_column
MsgBox "byref:" & last_column
trying_byval v:=last_column
MsgBox "byval:" & last_column
End Sub
Sub trying_byref(ByRef x)
x = 111
End Sub
Sub trying_byval(ByVal v) '<--not ByRef, that was in sub trying_byref.
v = 222
MsgBox "In Here:" & v
End Sub
ByRef, um valor terá 2 endereços
Então, se x= 80 (80 é o valor e x é o endereço, então, por exemplo, a variável y pode ser 80 também e, portanto, 80 pode ser acessada por x e y)
Respostas de @Tom e @kelloti são úteis.Aqui está um exemplo de código para ilustrar melhor:
Private Function ValMessage(ByVal SomeMessage As String)
SomeMessage = "Val Val Val" ' <-- this variable modification doesn't persist after the function finishes execution
ValMessage = "Some Return Value"
End Function
Private Function RefMessage(ByRef SomeMessage As String)
SomeMessage = "Ref Ref Ref" ' <-- this variable modification persists even after the function finishes execution
RefMessage = "Some Return Value"
End Function
Private Sub DoStuff()
Dim OriginalMessage As String
Dim OtherMessage As String
Dim AnotherMessage As String
OriginalMessage = "Original"
MsgBox ("ORIGINAL: " & OriginalMessage) '--> "Original"
OtherMessage = ValMessage(OriginalMessage)
MsgBox ("ORIGINAL: " & OriginalMessage) '--> "Original"
AnotherMessage = RefMessage(OriginalMessage)
MsgBox ("ORIGINAL: " & OriginalMessage) '--> "Ref Ref Ref" <--- this is the difference when you pass a paramter by reference
End Sub
Vou tentar explicar a diferença em palavras simples.
-
passar argumento por valor torna-o apenas parâmetro de entrada.Esta é a maneira mais segura, portanto, é usada por padrão em 95% dos casos.
-
passar argumento por referência torna-o parâmetro de entrada e saída.O parâmetro de saída pode ser alterado dentro da função, o que cria um efeito colateral raramente usado.