ref (Referencia de C#)ref (C# Reference)

La palabra clave ref indica un valor que se ha pasado mediante referencia.The ref keyword indicates a value that is passed by reference. Se usa en cuatro contextos diferentes:It is used in four different contexts:

  • En una firma del método y en una llamada al método, para pasar un argumento a un método mediante referencia.In a method signature and in a method call, to pass an argument to a method by reference. Para más información, vea Pasar un argumento mediante referencia.For more information, see Passing an argument by reference.
  • En una firma del método, para devolver un valor al autor de la llamada mediante referencia.In a method signature, to return a value to the caller by reference. Para obtener más información, consulte Valores devueltos de referencia.For more information, see Reference return values.
  • En un cuerpo de miembro, para indicar que un valor devuelto de referencia se almacena localmente como una referencia que el autor de la llamada pretende modificar o, en general, que una variable local accede a otro valor por referencia.In a member body, to indicate that a reference return value is stored locally as a reference that the caller intends to modify or, in general, a local variable accesses another value by reference. Para más información, vea Variables locales de tipo ref.For more information, see Ref locals.
  • En una declaración struct para declarar ref struct o readonly ref struct.In a struct declaration to declare a ref struct or a readonly ref struct. Para más información, vea Tipo de estructura de referencia.For more information, see ref struct types.

Pasar un argumento mediante referenciaPassing an argument by reference

Cuando se usa en una lista de parámetros del método, la palabra clave ref indica que un argumento se ha pasado mediante referencia, no por valor.When used in a method's parameter list, the ref keyword indicates that an argument is passed by reference, not by value. La palabra clave ref hace que el parámetro formal sea un alias para el argumento, que debe ser una variable.The ref keyword makes the formal parameter an alias for the argument, which must be a variable. En otras palabras, cualquier operación en el parámetro se realiza en el argumento.In other words, any operation on the parameter is made on the argument. Por ejemplo, si el autor de la llamada pasa una expresión de variable local o una expresión de acceso de elemento de matriz, y el método llamado reemplaza el objeto al que hace referencia el parámetro ref, entonces la variable local del autor de la llamada o el elemento de matriz hace ahora referencia al nuevo objeto cuando el método devuelve.For example, if the caller passes a local variable expression or an array element access expression, and the called method replaces the object to which the ref parameter refers, then the caller’s local variable or the array element now refers to the new object when the method returns.

Nota

No confunda el concepto de pasar por referencia con el concepto de tipos de referencia.Do not confuse the concept of passing by reference with the concept of reference types. Estos dos conceptos no son lo mismo.The two concepts are not the same. Un parámetro de método puede ser modificado por ref independientemente de si se trata de un tipo de valor o de un tipo de referencia.A method parameter can be modified by ref regardless of whether it is a value type or a reference type. No hay ninguna conversión boxing de un tipo de valor cuando se pasa por referencia.There is no boxing of a value type when it is passed by reference.

Para usar un parámetro ref, la definición de método y el método de llamada deben utilizar explícitamente la palabra clave ref, como se muestra en el ejemplo siguiente.To use a ref parameter, both the method definition and the calling method must explicitly use the ref keyword, as shown in the following example.

void Method(ref int refArgument)
{
    refArgument = refArgument + 44;
}

int number = 1;
Method(ref number);
Console.WriteLine(number);
// Output: 45

Un argumento que se pasa a un parámetro ref o in debe inicializarse antes de pasarlo.An argument that is passed to a ref or in parameter must be initialized before it is passed. En esto difiere de los parámetros out, cuyos argumentos no tienen que inicializarse explícitamente antes de pasarlos.This differs from out parameters, whose arguments do not have to be explicitly initialized before they are passed.

Los miembros de una clase no pueden tener signaturas que se diferencien solo por ref, in o out.Members of a class can't have signatures that differ only by ref, in, or out. Si la única diferencia entre dos miembros de un tipo es que uno de ellos tiene un parámetro ref y el otro tiene un parámetro out o in, se produce un error de compilador.A compiler error occurs if the only difference between two members of a type is that one of them has a ref parameter and the other has an out, or in parameter. El código siguiente, por ejemplo, no se compila.The following code, for example, doesn't compile.

class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded 
    // methods that differ only on ref and out".
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
}

En cambio, los métodos pueden sobrecargarse cuando un método tiene un parámetro ref, in o out y el otro tiene un parámetro de valor, como se muestra en el ejemplo siguiente.However, methods can be overloaded when one method has a ref, in, or out parameter and the other has a value parameter, as shown in the following example.

class RefOverloadExample
{
    public void SampleMethod(int i) { }
    public void SampleMethod(ref int i) { }
}

En otras situaciones que requieran firma coincidente, como ocultar o reemplazar, in, ref y out forman parte de la signatura y no coinciden entre sí.In other situations that require signature matching, such as hiding or overriding, in, ref, and out are part of the signature and don't match each other.

Las propiedades no son variables.Properties are not variables. Son métodos y no se pueden pasar a parámetros ref.They are methods, and cannot be passed to ref parameters.

Las palabras clave ref, in y out no pueden usarse para estos tipos de métodos:You can't use the ref, in, and out keywords for the following kinds of methods:

  • Métodos asincrónicos, que se definen mediante el uso del modificador async.Async methods, which you define by using the async modifier.
  • Métodos de iterador, que incluyen una instrucción yield return o yield break.Iterator methods, which include a yield return or yield break statement.

Paso de un argumento mediante referencia: Un ejemploPassing an argument by reference: An example

En los ejemplos anteriores se pasan tipos de valor mediante referencia.The previous examples pass value types by reference. También se puede usar la palabra clave ref para pasar tipos de referencia mediante referencia.You can also use the ref keyword to pass reference types by reference. Pasar un tipo de referencia por referencia permite que el método llamado pueda reemplazar el objeto al que hace referencia el parámetro de referencia en el autor de la llamada.Passing a reference type by reference enables the called method to replace the object to which the reference parameter refers in the caller. La ubicación de almacenamiento del objeto se pasa al método como el valor del parámetro de referencia.The storage location of the object is passed to the method as the value of the reference parameter. Si cambia el valor de la ubicación de almacenamiento del parámetro (para que apunte a un nuevo objeto), también debe cambiar la ubicación de almacenamiento a la que se refiere el autor de la llamada.If you change the value in the storage location of the parameter (to point to a new object), you also change the storage location to which the caller refers. En el ejemplo siguiente se pasa una instancia de un tipo de referencia como un parámetro ref.The following example passes an instance of a reference type as a ref parameter.

class Product
{
    public Product(string name, int newID)
    {
        ItemName = name;
        ItemID = newID;
    }

    public string ItemName { get; set; }
    public int ItemID { get; set; }
}

private static void ChangeByReference(ref Product itemRef)
{
    // Change the address that is stored in the itemRef parameter.   
    itemRef = new Product("Stapler", 99999);

    // You can change the value of one of the properties of
    // itemRef. The change happens to item in Main as well.
    itemRef.ItemID = 12345;
}

private static void ModifyProductsByReference()
{
    // Declare an instance of Product and display its initial values.
    Product item = new Product("Fasteners", 54321);
    System.Console.WriteLine("Original values in Main.  Name: {0}, ID: {1}\n",
        item.ItemName, item.ItemID);

    // Pass the product instance to ChangeByReference.
    ChangeByReference(ref item);
    System.Console.WriteLine("Back in Main.  Name: {0}, ID: {1}\n",
        item.ItemName, item.ItemID);
}

// This method displays the following output:
// Original values in Main.  Name: Fasteners, ID: 54321
// Back in Main.  Name: Stapler, ID: 12345        

Para obtener más información sobre cómo pasar tipos de referencia por valor y por referencia, vea Pasar parámetros Reference-Type .For more information about how to pass reference types by value and by reference, see Passing Reference-Type Parameters.

Valores devueltos de referenciaReference return values

Los valores devueltos de referencia (o valores devueltos de tipo ref) son valores que devuelve un método mediante referencia al autor de la llamada.Reference return values (or ref returns) are values that a method returns by reference to the caller. Es decir, el autor de la llamada puede modificar el valor devuelto por un método, y ese cambio se refleja en el estado del objeto que contiene el método.That is, the caller can modify the value returned by a method, and that change is reflected in the state of the object that contains the method.

Un valor devuelto de referencia se define mediante la palabra clave ref:A reference return value is defined by using the ref keyword:

  • En la firma del método.In the method signature. Por ejemplo, en la firma de método siguiente se indica que el método GetCurrentPrice devuelve un valor Decimal por referencia.For example, the following method signature indicates that the GetCurrentPrice method returns a Decimal value by reference.
public ref decimal GetCurrentPrice()
  • Entre el token return y la variable devuelta en una instrucción return en el método.Between the return token and the variable returned in a return statement in the method. Por ejemplo:For example:
return ref DecimalArray[0];

Para que el autor de la llamada modifique el estado del objeto, el valor devuelto de referencia debe almacenarse en una variable que se defina explícitamente como una variable local de tipo ref.In order for the caller to modify the object's state, the reference return value must be stored to a variable that is explicitly defined as a ref local.

El método llamado también puede declarar el valor devuelto como ref readonly para devolver el valor por referencia y exigir que el código de llamada no pueda modificar el valor devuelto.The called method may also declare the return value as ref readonly to return the value by reference, and enforce that the calling code cannot modify the returned value. El método de llamada puede evitar copiar el valor devuelto mediante el almacenamiento del valor en una variable de tipo ref readonly.The calling method can avoid copying the returned valued by storing the value in a local ref readonly variable.

Para obtener un ejemplo, vea Un ejemplo de valores devueltos y variables locales de tipo ref.For an example, see A ref returns and ref locals example.

Variables locales de tipo refRef locals

Una variable local de tipo ref se usa para hacer referencia a valores devueltos con return ref.A ref local variable is used to refer to values returned using return ref. Una variable local de tipo ref no se puede inicializar en un valor devuelto de tipo no ref.A ref local variable cannot be initialized to a non-ref return value. Es decir, el lado derecho de la inicialización debe ser una referencia.In other words, the right hand side of the initialization must be a reference. Cualquier modificación en el valor de la variable local de tipo ref se refleja en el estado del objeto cuyo método ha devuelto el valor mediante referencia.Any modifications to the value of the ref local are reflected in the state of the object whose method returned the value by reference.

Defina una variable local de tipo ref mediante la palabra clave ref antes de la declaración de variable, así como inmediatamente antes de la llamada al método que devuelve el valor mediante referencia.You define a ref local by using the ref keyword before the variable declaration, as well as immediately before the call to the method that returns the value by reference.

Por ejemplo, en la siguiente instrucción se define un valor de variable local de tipo ref que se devuelve mediante un método denominado GetEstimatedValue:For example, the following statement defines a ref local value that is returned by a method named GetEstimatedValue:

ref decimal estValue = ref Building.GetEstimatedValue();

Puede acceder a un valor por referencia de la misma manera.You can access a value by reference in the same way. En algunos casos, acceder a un valor por referencia aumenta el rendimiento, ya que evita una operación de copia potencialmente cara.In some cases, accessing a value by reference increases performance by avoiding a potentially expensive copy operation. Por ejemplo, en la instrucción siguiente se muestra cómo es posible definir un valor local de referencia que se usa para hacer referencia a un valor.For example, the following statement shows how one can define a ref local value that is used to reference a value.

ref VeryLargeStruct reflocal = ref veryLargeStruct;

Tenga en cuenta que en ambos ejemplos la palabra clave ref debe usarse en ambos lugares. De lo contrario, el compilador genera el error CS8172, "No se puede inicializar una variable por referencia con un valor".Note that in both examples the ref keyword must be used in both places, or the compiler generates error CS8172, "Cannot initialize a by-reference variable with a value."

A partir C# 7.3, la variable de iteración de la instrucción foreach puede ser una variable ref local o ref readonly local.Beginning with C# 7.3, the iteration variable of the foreach statement can be ref local or ref readonly local variable. Para más información, vea el artículo sobre la instrucción foreach.For more information, see the foreach statement article.

Variables locales de tipo ref readonlyRef readonly locals

Una variable local de tipo ref readonly se usa para hacer referencia a los valores devueltos por el método o la propiedad que tiene ref readonly en su firma y utiliza return ref.A ref readonly local is used to refer to values returned by the method or property that has ref readonly in its signature and uses return ref. Una variable ref readonly combina las propiedades de una ref variable local con una variable readonly: es un alias para el almacenamiento al que se asigna y no se puede modificar.A ref readonly variable combines the properties of a ref local variable with a readonly variable: it is an alias to the storage it's assigned to, and it cannot be modified.

Un ejemplo de valores devueltos y variables locales de tipo refA ref returns and ref locals example

En el ejemplo siguiente se define una clase Book que tiene dos campos String, Title y Author.The following example defines a Book class that has two String fields, Title and Author. También define una clase BookCollection que incluye una matriz privada de objetos Book.It also defines a BookCollection class that includes a private array of Book objects. Los objetos book individuales se devuelven mediante referencia llamando a su método GetBookByTitle.Individual book objects are returned by reference by calling its GetBookByTitle method.


public class Book
{
    public string Author;
    public string Title;
}

public class BookCollection
{
    private Book[] books = { new Book { Title = "Call of the Wild, The", Author = "Jack London" },
                        new Book { Title = "Tale of Two Cities, A", Author = "Charles Dickens" }
                       };
    private Book nobook = null;

    public ref Book GetBookByTitle(string title)
    {
        for (int ctr = 0; ctr < books.Length; ctr++)
        {
            if (title == books[ctr].Title)
                return ref books[ctr];
        }
        return ref nobook;
    }

    public void ListBooks()
    {
        foreach (var book in books)
        {
            Console.WriteLine($"{book.Title}, by {book.Author}");
        }
        Console.WriteLine();
    }
}

Cuando el autor de la llamada almacena el valor devuelto mediante el método GetBookByTitle como una variable local de tipo ref, los cambios que el autor de la llamada realiza en el valor devuelto se reflejan en el objeto BookCollection, como se muestra en el ejemplo siguiente.When the caller stores the value returned by the GetBookByTitle method as a ref local, changes that the caller makes to the return value are reflected in the BookCollection object, as the following example shows.

var bc = new BookCollection();
bc.ListBooks();

ref var book = ref bc.GetBookByTitle("Call of the Wild, The");
if (book != null)
    book = new Book { Title = "Republic, The", Author = "Plato" };
bc.ListBooks();
// The example displays the following output:
//       Call of the Wild, The, by Jack London
//       Tale of Two Cities, A, by Charles Dickens
//       
//       Republic, The, by Plato
//       Tale of Two Cities, A, by Charles Dickens

Tipos de estructura de referenciaRef struct types

La incorporación del modificador ref a una declaración struct define que las instancias de ese tipo se deben asignar a la pila.Adding the ref modifier to a struct declaration defines that instances of that type must be stack allocated. En otras palabras, las instancias de estos tipos no se pueden crear nunca en el montón como un miembro de otra clase.In other words, instances of these types can never be created on the heap as a member of another class. La principal motivación para esta característica era Span<T> y las estructuras relacionadas.The primary motivation for this feature was Span<T> and related structures.

El objetivo de mantener un tipo ref struct como una variable asignada a la pila presenta varias reglas que el compilador exige para todos los tipos ref struct.The goal of keeping a ref struct type as a stack-allocated variable introduces several rules that the compiler enforces for all ref struct types.

  • No puede encerrar un valor de ref struct.You can't box a ref struct. No puede asignar un tipo ref struct a una variable de tipo object, dynamic o cualquier tipo de interfaz.You cannot assign a ref struct type to a variable of type object, dynamic, or any interface type.
  • Los tipos ref struct no pueden implementar interfaces.ref struct types cannot implement interfaces.
  • No se puede declarar ref struct como miembro de campo de una clase o una estructura normal.You can't declare a ref struct as a field member of a class or a normal struct. Esto incluye la declaración de una propiedad implementada automáticamente, lo que crea un campo de respaldo generado por el compilador.This includes declaring an auto-implemented property, which creates a compiler generated backing field.
  • No puede declarar variables locales que sean tipos ref struct en métodos asincrónicos.You cannot declare local variables that are ref struct types in async methods. Puede declararlas en los métodos sincrónicos que devuelven tipos similares a Task, Task<TResult> o Task.You can declare them in synchronous methods that return Task, Task<TResult> or Task-like types.
  • No puede declarar las variables locales de ref struct en iteradores.You cannot declare ref struct local variables in iterators.
  • No puede capturar variables ref struct en expresiones lambda o funciones locales.You cannot capture ref struct variables in lambda expressions or local functions.

Estas restricciones aseguran que no se usará por error un valor ref struct de manera que pueda promoverlo al montón administrado.These restrictions ensure you don't accidentally use a ref struct in a manner that could promote it to the managed heap.

Puede combinar modificadores para declarar una estructura como readonly ref.You can combine modifiers to declare a struct as readonly ref. readonly ref struct combina las ventajas y las restricciones de las declaraciones ref struct y readonly struct.A readonly ref struct combines the benefits and restrictions of ref struct and readonly struct declarations.

Especificación del lenguaje C#C# language specification

Para obtener más información, consulte la Especificación del lenguaje C#.For more information, see the C# Language Specification. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.The language specification is the definitive source for C# syntax and usage.

Vea tambiénSee also