Compatibilidad con valores devueltos de referencia (Visual Basic)

A partir de C# 7.0, el lenguaje C# admite valores devueltos de referencia. Una manera de entender 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 autor de la llamada. Cuando un método proporciona un valor devuelto de referencia a un llamador, las modificaciones realizadas en el valor devuelto de referencia por el autor de la llamada se reflejan en los datos del método llamado.

Visual Basic no permite crear métodos con valores devueltos de referencia, pero permite consumir valores devueltos de referencia. 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 reflejan en los datos del método llamado.

Modificar el valor devuelto de referencia directamente

Para los métodos que siempre tienen éxito y no tienen parámetros, puede modificar el valor devuelto ByRef 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 NumericValue.IncrementValue un método 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;
   }
}

A continuación, el autor de la llamada modifica el valor devuelto de referencia en el siguiente Visual Basic ejemplo. Tenga en cuenta que la línea con la llamada al 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, puede que no siempre sea conveniente modificar directamente el valor devuelto de referencia de una llamada al método. Por ejemplo, un método de búsqueda que devuelve una cadena puede no encontrar siempre una coincidencia. En ese caso, desea modificar el valor devuelto de referencia solo si la búsqueda se realiza correctamente.

En el siguiente ejemplo de C# se muestra este escenario. Define una clase escrita en C# que incluye un método que encuentra la palabra siguiente en una oración que Sentence FindNext 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 autor de la llamada también puede modificarlo y esa modificación se refleja en los datos contenidos internamente en la Sentence clase .

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

La modificación directa del valor devuelto de referencia en este caso no es confiable, ya que es posible que la llamada al método no encuentre una coincidencia y devuelva la primera palabra de la frase. En ese caso, el autor de la llamada modificará accidentalmente la primera palabra de la frase. Esto podría evitarse si el autor de la llamada devolvía null un (o Nothing en Visual Basic). Pero en ese caso, al intentar modificar una cadena cuyo valor es Nothing , se produce una NullReferenceException excepción . Si también podría ser impedido por el autor de la llamada que devuelve , pero esto requiere que el autor de la llamada defina una variable de String.Empty cadena cuyo valor sea String.Empty . Aunque el autor de la llamada puede 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 almacenadas por la Sentence clase .

La mejor manera de controlar este escenario es pasar el valor devuelto de referencia por referencia a un método auxiliar. A continuación, el método auxiliar contiene la lógica para determinar si la llamada al método se ha hecho correctamente y, si lo hizo, para modificar el valor devuelto de referencia. En el ejemplo siguiente 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.

Consulta también