ByVal, ByRef, Optional e ParamArray
Introdução
Por cada vez que criamos um método, é nos impingido o ByVal
antes da nossa variável de argumento. O que são afinal estas designações e por que devemos saber usá-las? Estas "keywords" são na verdade muito importantes no que toca ao método como os nossos argumentos são passados.
ByVal
O ByVal
é a "keyword" que é automáticamente inserida atrás das nossas variáveis de argumentos. Exprimentemos o seguinte bloco de código:
Private Sub FazerAlgo(Valor1 As String, Valor2 As String)
End Sub
Ao passarmos para a próxima linha, ou clicarmos em qualquer lugar no editor, reparamos que as palavras ByVal
são automaticamente inseridas atrás das variáveis Valor1
e Valor2
. Passamos a ter:
Private Sub FazerAlgo(ByVal Valor1 As String, ByVal Valor2 As String)
End Sub
ByVal
provoca a passagem de um valor. Qualquer valor ou variável que seja inserida em argumento é passada para o método e qualquer alteração a este valor, dentro do método, não se reflecte em mais lado nenhum senão no próprio sub. Por exemplo:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim Palavra1 As String = "Olá"
Dim Palavra2 As String = "Mundo"
FazerAlgo(Palavra1, Palavra2)
MessageBox.Show(Palavra1 & " " & Palavra2)
End Sub
Private Sub FazerAlgo(ByVal Valor1 As String, ByVal Valor2 As String)
Valor1 = "Adeus"
MessageBox.Show(Valor1 & " " & Valor2)
End Sub
End Class
Os valores das variáveis Palavra1
e Palavra2
são passados para o método FazerAlgo
. Ainda que a variável Valor1
seja alterada para Adeus
, como se verifica na primeira MessageBox
, a segunda MessageBox
continua a apresentar-nos Olá
.
Nota: Primeira e segunda messagebox refere-se ao fluxo e não à ordem linear.
ByRef
ByVal
provoca a referência de um valor. É importante perceber a diferença entre oferecer um valor e oferecer uma referência. Qualquer alteração a um valor, não se reflecte na origem do dado, mas uma alteração a uma referência altera a origem do dado, uma vez que se trata de uma referência ao dado original. Senão vejamos:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim Palavra1 As String = "Olá"
Dim Palavra2 As String = "Mundo"
FazerAlgo(Palavra1, Palavra2)
MessageBox.Show(Palavra1 & " " & Palavra2)
End Sub
Private Sub FazerAlgo(ByRef Valor1 As String, ByRef Valor2 As String)
Valor1 = "Adeus"
MessageBox.Show(Valor1 & " " & Valor2)
End Sub
End Class
Este bloco é práticamente idêntico ao anterior, excepto a "keyword" atrás das variáveis. Com ByRef
, verificará agora que ambas as MessageBox
vão informar Adeus Mundo
, pois a variável Valor1
, no método, foi alterada, causando alteração na sua referência original, a Palavra1
do Form_Load
. Isto é muito importante, pois estando ciente desta diferença é possível, por exemplo, uma função que devolva uma série de valores. Por exemplo:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim ResultadoDivisao As Double
If Dividir(10, 2, ResultadoDivisao) = False Then MsgBox("Não podes dividir por zero!") : Exit Sub
MessageBox.Show(ResultadoDivisao)
If Dividir(10, 0, ResultadoDivisao) = False Then MsgBox("Não podes dividir por zero!") : Exit Sub
MessageBox.Show(ResultadoDivisao)
End Sub
Private Function Dividir(ByVal Parcela1 As Double, ByVal Parcela2 As Double, ByRef Resultado As Double) As Boolean
If Parcela1 = 0 Or Parcela2 = 0 Then Return False
Resultado = Parcela1 / Parcela2
Return True
End Function
End Class
No exemplo, enviamos o valor das parcelas e uma referência à variável ResultadoDivisao
. Ao chamar o método, são nos devolvidos dois valores: o ResultadoDivisao
, por referência, e o Boolean
a informar o sucesso. Ao correr o exemplo, verificamos que a primeira MessageBox
informa o resultado da divisão, passado por referência, e a segunda MessageBox
informa que uma das parcelas é zero, porque o boolean de retorno volta a zero (False
). Desta forma, conseguimos um método que devolve dois valores: uma variável do tipo Double
e outra do tipo Boolean
.
Optional
Em adição ao ByVal
e ByRef
, ainda podemos determinar o argumento como Optional
, ou opcional. Ao marcarmos um argumento como opcional, ao chamar o método podemos optar por não enviar um valor nesse argumento, o que pode ser usado para determinadas finalidades. Como o argumento existe, e tem de transportar um valor, ao definirmos o argumento temos obrigatóriamente que lhe atribuír um valor para ser usado como o valor padrão. Ainda que optemos por não passar nenhum valor, é o valor padrão que lhe está atribuído. Por exemplo:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MessageBox.Show(Unir("Olá ", "mundo! ", ))
MessageBox.Show(Unir("Olá ", , "Sou eu de novo!"))
MessageBox.Show(Unir("Olá ", "mundo! ", "Sou eu de novo!"))
End Sub
Private Function Unir(ByVal Palavra1 As String, Optional ByVal Palavra2 As String = "", Optional ByVal Palavra3 As String = "") As String
Return Palavra1 & Palavra2 & Palavra3
End Function
End Class
Os argumentos Palavra2
e Palavra3
são opcionais. Podemos optar por enviar valores ou não. O método está preparado para não receber valores nos argumentos da chamada. Como o valor padrão, é neste caso nada, ou "", ao não enviarmos o argumento estamos a ignorá-lo na união.
Importante: Os argumentos opcionais têm obrigatóriamente que ser os últimos argumentos do método.
Importante: Nem todos os tipos de dados podem ser passados por argumentos opcionais. Tipos de dados compostos são um exemplo de um tipo de dados não aceite.
ParamArray
Para além do ByVal
, ByRef
e Optional
, podemos também definir um ParamArray
que é uma matriz de elementos de um determinado tipo. À semelhança do Optional
, o ParamArray
só pode ser o último dos argumentos.
Exemplo:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
MessageBox.Show(Unir("Olá, ", "está ", "tudo ", "bem?"))
End Sub
Private Function Unir(ParamArray Palavras() As String) As String
Dim Resultado As String = String.Empty
For Each S As String In Palavras
Resultado &= S
Next
Return Resultado
End Function
End Class