Compatibilidad con valores devueltos de referencia (Visual Basic)

El lenguaje C# admite valores devueltos de referencia. Una manera de comprender los valores devueltos de referencia es que son lo contrario de los argumentos que se pasan por referencia a un método. Cuando se modifica un argumento pasado por referencia, los cambios se reflejan en el valor de la variable en el llamador. Cuando un método proporciona un valor devuelto de referencia a un llamador, las modificaciones realizadas en el valor devuelto de referencia por el llamador se reflejan en los datos del método llamado.

Visual Basic no le permite crear métodos con valores devueltos de referencia, pero le permite consumir valores de este tipo. En otras palabras, puede llamar a un método con un valor devuelto de referencia y modificar ese valor devuelto, y los cambios en el valor devuelto de referencia se reflejarán en los datos del método llamado.

Modificación directa del valor devuelto de referencia

En los métodos que siempre se ejecutan correctamente y no tienen parámetros ByRef, puede modificar el valor devuelto de referencia directamente. Para ello, asigne el nuevo valor a las expresiones que devuelven el valor devuelto de referencia.

En el siguiente ejemplo de C# se define un método NumericValue.IncrementValue que incrementa un valor interno y lo devuelve como un valor devuelto de referencia.

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;
   }
}

Después, en el siguiente ejemplo de Visual Basic, el llamador modifica el valor devuelto de referencia. Tenga en cuenta que la línea con la llamada de método NumericValue.IncrementValue no asigna un valor al método. En su lugar, asigna un valor al valor devuelto de referencia devuelto por el 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

Uso de un método auxiliar

En otros casos, es posible que la modificación del valor devuelto de referencia de una llamada de método no siempre sea deseable. Por ejemplo, puede que un método de búsqueda que devuelve una cadena no encuentre siempre una coincidencia. En ese caso, solo le interesa modificar el valor devuelto de referencia si la búsqueda se realiza correctamente.

Este escenario se ilustra en el siguiente ejemplo de C#. Se define una clase Sentence, escrita en C#, que incluye un método FindNext que busca la siguiente palabra de una frase que comienza con una subcadena especificada. La cadena se devuelve como un valor devuelto de referencia, y una variable Boolean que se ha pasado mediante referencia al método indica si la búsqueda se ha realizado correctamente. El valor devuelto de referencia indica que, además de leer el valor devuelto, el llamador también puede modificarlo y esa modificación se refleja en los datos contenidos internamente en la clase Sentence.

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();
    }
}

En este caso, la modificación directa del valor devuelto de referencia no es confiable, ya que la llamada al método puede no encontrar una coincidencia y devolver la primera palabra de la oración. Si eso ocurre, el llamador modificará accidentalmente esa primera palabra. El autor de la llamada podría evitarlo devolviendo null (o Nothing en Visual Basic). Pero, en ese caso, al intentar modificar una cadena cuyo valor es Nothing, se produce una excepción NullReferenceException. Otra forma de evitarlo es si el llamador devuelve String.Empty, pero esto requiere que el llamador defina una variable de cadena cuyo valor sea String.Empty. Aunque el llamador pueda modificar esa cadena, la propia modificación no tiene ningún propósito, ya que la cadena modificada no tiene ninguna relación con las palabras de la oración almacenada por la clase Sentence.

La mejor manera de controlar este escenario es pasar por referencia el valor devuelto de referencia a un método auxiliar. Así, el método auxiliar tendrá la lógica para determinar si la llamada de método se realiza correctamente y, si es así, para modificar el valor devuelto de referencia. En el siguiente ejemplo se proporciona una posible implementación.

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.

Consulte también