Suporte para valores de retorno de referência (Visual Basic)

O C# dá suporte a valores de referência de devolução. Uma maneira de entender os valores retornados de referência é que eles são o oposto dos argumentos que são passados por referência a um método. Quando um argumento passado por referência é modificado, as alterações são refletidas no valor da variável no chamador. Quando um método fornece um valor de retorno de referência para um chamador, as modificações feitas no valor de retorno de referência pelo chamador são refletidas nos dados do método chamado.

O Visual Basic não permite a criação de métodos com valores retornados de referência, mas isso não permite o consumo e a modificação de valores de retorno de referência. Em outras palavras, você pode chamar um método com um valor de retorno de referência e modificar esse valor retornado, e as alterações no valor de retorno de referência são refletidas nos dados do método chamado.

Modificando o valor de retorno de ref diretamente

Para métodos que sempre têm êxito e não ByRef têm parâmetros, você pode modificar o valor de retorno de referência diretamente. Faça isso atribuindo o novo valor às expressões que retornam o valor de retorno de referência.

O exemplo de C# a seguir define um NumericValue.IncrementValue método que incrementa um valor interno e o retorna como um valor de retorno de referência.

using System;

public class NumericValue
{
   private int value = 0;

   public NumericValue(int value)
   {
      this.value = value;
   }

   public ref int IncrementValue()
   {
      value++;
      return ref value;
   }

   public int GetValue()
   {
      return value;
   }
}

O valor de retorno de referência é modificado pelo chamador no exemplo do Visual Basic a seguir. Observe que a linha com a NumericValue.IncrementValue chamada de método não atribui um valor ao método. Em vez disso, ele atribui um valor ao valor de retorno de referência retornado pelo método.

Module Example
   Public Sub Main()
      Dim n As New NumericValue(15)
      n.IncrementValue() += 12
      Console.WriteLine(n.GetValue) 
   End Sub
End Module
' Output:   28

Usando um método auxiliar

Em outros casos, modificar o valor de retorno de referência de uma chamada de método diretamente pode nem sempre ser desejável. Por exemplo, um método de pesquisa que retorna uma cadeia de caracteres pode nem sempre encontrar uma correspondência. Nesse caso, você deseja modificar o valor de retorno de referência somente se a pesquisa for bem-sucedida.

O exemplo C# a seguir ilustra esse cenário. Por exemplo, a classe Sentence a seguir escrita em C# inclui um método FindNext que localiza a próxima palavra em uma sentença que começa com uma substring de caracteres especificada. A cadeia de caracteres é retornada como um valor retornado de referência e uma variável Boolean passada pela referência para o método indica se a pesquisa foi bem-sucedida. O valor de retorno de referência indica que, além de ler o valor retornado, o chamador também pode modificá-lo e essa modificação é refletida nos dados contidos internamente na Sentence classe.

using System;

public class Sentence
{
    private string[] words;
    private int currentSearchPointer;

    public Sentence(string sentence)
    {
        words = sentence.Split(' ');
        currentSearchPointer = -1;
    }

    public ref string FindNext(string startWithString, ref bool found)
    {
        for (int count = currentSearchPointer + 1; count < words.Length; count++)
        {
            if (words[count].StartsWith(startWithString))
            {
                currentSearchPointer = count;
                found = true;
                return ref words[currentSearchPointer];
            }
        }
        currentSearchPointer = -1;
        found = false;
        return ref words[0];
    }

    public string GetSentence()
    {
        string stringToReturn = null;
        foreach (var word in words)
            stringToReturn += $"{word} ";

        return stringToReturn.Trim();
    }
}

Modificar diretamente o valor de retorno de referência nesse caso não é confiável, pois a chamada de método pode não encontrar uma correspondência e retornar a primeira palavra na frase. Nesse caso, o chamador modificará inadvertidamente a primeira palavra da frase. Isso pode ser impedido pelo chamador retornar um null (ou Nothing no Visual Basic). Mas, nesse caso, tentar modificar uma cadeia de caracteres cujo valor é Nothing gerado um NullReferenceException. Se também puder ser impedido pelo retorno do chamador String.Empty, mas isso exigirá que o chamador defina uma variável de cadeia de caracteres cujo valor seja String.Empty. Embora o chamador possa modificar essa cadeia de caracteres, a modificação em si não serve para nenhuma finalidade, uma vez que a cadeia de caracteres modificada não tem relação com as palavras na frase armazenada pela Sentence classe.

A melhor maneira de lidar com esse cenário é passar o valor de retorno de referência por referência a um método auxiliar. Em seguida, o método auxiliar contém a lógica para determinar se a chamada de método foi bem-sucedida e, se o fez, para modificar o valor de retorno de referência. O exemplo a seguir fornece uma possível implementação.

Module Example
   Public Sub Main()
      Dim sentence As New Sentence("A time to see the world is now.")
      Dim found = False
      Dim returns = RefHelper(sentence.FindNext("A", found), "A good", found) 
      Console.WriteLine(sentence.GetSentence()) 
   End Sub
   
   Private Function RefHelper(ByRef stringFound As String, replacement As String, success As Boolean) _ 
                    As (originalString As String, found As Boolean) 
      Dim originalString = stringFound
      If found Then stringFound = replacement
      Return (originalString, found)   
   End Function
End Module
' The example displays the following output:
'      A good time to see the world is now.

Confira também