Instrucciones de declaración

Una instrucción de declaración declara una nueva variable local, constante local o variable local de referencia. Para declarar una variable local, especifique su tipo y proporcione su nombre. Puede declarar varias variables del mismo tipo en una instrucción, tal como se muestra en el ejemplo siguiente:

string greeting;
int a, b, c;
List<double> xs;

En una instrucción de declaración, también puede inicializar una variable con su valor inicial:

string greeting = "Hello";
int a = 3, b = 2, c = a + b;
List<double> xs = new();

Los ejemplos anteriores especifican explícitamente el tipo de una variable. También puede permitir que el compilador infiera el tipo de una variable a partir de su expresión de inicialización. Para ello, use la palabra clave var en lugar del nombre de un tipo. Para más información, vea la sección Variables locales con asignación implícita de tipos.

Para declarar una constante local, use la palabra clave const, como se muestra en el ejemplo siguiente:

const string Greeting = "Hello";
const double MinLimit = -10.0, MaxLimit = -MinLimit;

Al declarar una constante local, también debe inicializarla.

Para obtener información sobre las variables de referencia locales, consulte la sección Variables de referencia.

Variables locales con asignación implícita de tipos

Al declarar una variable local, puede permitir que el compilador infiera el tipo de la variable a partir de la expresión de inicialización. Para ello, use la palabra clave var en lugar del nombre de un tipo:

var greeting = "Hello";
Console.WriteLine(greeting.GetType());  // output: System.String

var a = 32;
Console.WriteLine(a.GetType());  // output: System.Int32

var xs = new List<double>();
Console.WriteLine(xs.GetType());  // output: System.Collections.Generic.List`1[System.Double]

Como se muestra en el ejemplo anterior, las variables locales con asignación implícita de tipos están fuertemente tipadas.

Nota:

Cuando se usa var en el contexto compatible con valores null habilitado y el tipo de una expresión de inicialización es un tipo de referencia, el compilador siempre infiere un tipo de referencia que acepta valores null aunque el tipo de una expresión de inicialización no acepta valores null.

Un uso común de var es con la expresión de invocación del constructor. El uso de var permite no repetir un nombre de tipo en una declaración de variable y una creación de instancias de objeto, como se muestra en el ejemplo siguiente:

var xs = new List<int>();

Puede usar una expresiónnew tipo de destino como alternativa:

List<int> xs = new();
List<int>? ys = new();

Al trabajar con tipos anónimos, debe usar variables locales con asignación implícita de tipos. En el ejemplo siguiente se muestra una expresión de consulta que usa un tipo anónimo para contener el nombre y el número de teléfono de un cliente:

var fromPhoenix = from cust in customers
                  where cust.City == "Phoenix"
                  select new { cust.Name, cust.Phone };

foreach (var customer in fromPhoenix)
{
    Console.WriteLine($"Name={customer.Name}, Phone={customer.Phone}");
}

En el ejemplo anterior, no se puede especificar explícitamente el tipo de la variable fromPhoenix. El tipo es IEnumerable<T>, pero en este caso, T es un tipo anónimo y no se puede proporcionar su nombre. Por eso es necesario usar var. Por el mismo motivo, debe usar var al declarar la variable de iteración customer en la instrucción foreach.

Para obtener más información sobre las variables locales con asignación implícita de tipos, vea Variables locales con asignación implícita de tipos.

En la coincidencia de patrones, la palabra clave var se usa en un patrón var.

Variables de referencia

Al declarar una variable local y agregar la palabra clave ref antes del tipo de la variable, se declara una variable de referencia o local ref:

ref int alias = ref variable;

Una variable de referencia es una variable que hace referencia a otra variable, que se denomina referencia. Es decir, una variable de referencia es un alias para su referente. Al asignar un valor a una variable de referencia, ese valor se asigna al referente. Cuando se lee el valor de una variable de referencia, se devuelve el valor del referente. En el ejemplo siguiente se muestra ese comportamiento:

int a = 1;
ref int alias = ref a;
Console.WriteLine($"(a, alias) is ({a}, {alias})");  // output: (a, alias) is (1, 1)

a = 2;
Console.WriteLine($"(a, alias) is ({a}, {alias})");  // output: (a, alias) is (2, 2)

alias = 3;
Console.WriteLine($"(a, alias) is ({a}, {alias})");  // output: (a, alias) is (3, 3)

Use el refoperador de asignación= ref para cambiar el referente de una variable de referencia, como se muestra en el ejemplo siguiente:

void Display(int[] s) => Console.WriteLine(string.Join(" ", s));

int[] xs = [0, 0, 0];
Display(xs);

ref int element = ref xs[0];
element = 1;
Display(xs);

element = ref xs[^1];
element = 3;
Display(xs);
// Output:
// 0 0 0
// 1 0 0
// 1 0 3

En el ejemplo anterior, la variable de referencia element se inicializa como un alias para el primer elemento de la matriz. A continuación, se reasigna ref para referir al último elemento de la matriz.

Puede definir una variable local ref readonly. No se puede asignar ningún valor a una variable ref readonly. Sin embargo, puede ref reasignar esta variable de referencia, como se muestra en el ejemplo siguiente:

int[] xs = [1, 2, 3];

ref readonly int element = ref xs[0];
// element = 100;  error CS0131: The left-hand side of an assignment must be a variable, property or indexer
Console.WriteLine(element);  // output: 1

element = ref xs[^1];
Console.WriteLine(element);  // output: 3

Puede asignar una devolución de referencia a una variable de referencia, como se muestra en el ejemplo siguiente:

using System;

public class NumberStore
{
    private readonly int[] numbers = [1, 30, 7, 1557, 381, 63, 1027, 2550, 511, 1023];

    public ref int GetReferenceToMax()
    {
        ref int max = ref numbers[0];
        for (int i = 1; i < numbers.Length; i++)
        {
            if (numbers[i] > max)
            {
                max = ref numbers[i];
            }
        }
        return ref max;
    }

    public override string ToString() => string.Join(" ", numbers);
}

public static class ReferenceReturnExample
{
    public static void Run()
    {
        var store = new NumberStore();
        Console.WriteLine($"Original sequence: {store.ToString()}");
        
        ref int max = ref store.GetReferenceToMax();
        max = 0;
        Console.WriteLine($"Updated sequence:  {store.ToString()}");
        // Output:
        // Original sequence: 1 30 7 1557 381 63 1027 2550 511 1023
        // Updated sequence:  1 30 7 1557 381 63 1027 0 511 1023
    }
}

En el ejemplo anterior, el método GetReferenceToMax es un método returns-by-ref. No devuelve el valor máximo, sino una devolución de referencia que es un alias para el elemento de matriz que contiene el valor máximo. El método Run asigna una devolución de referencia a la variable de referencia max. A continuación, con la asignación a max, actualiza el almacenamiento interno de la instancia store. También puede definir un método ref readonly. Los autores de la llamada de un método ref readonly no pueden asignar un valor a su valor devuelto de referencia.

La variable de iteración de la instrucción foreach puede ser una variable de referencia. Para obtener más información, consulte la sección instrucciones foreach del artículo Instrucciones de iteración.

En escenarios críticos para el rendimiento, el uso de variables y devoluciones de referencia podría aumentar el rendimiento evitando operaciones de copia potencialmente costosas.

El compilador garantiza que una variable de referencia no sobrevive a su referente y permanece válida durante toda su duración. Para obtener más información, consulte la sección Contextos seguros ref de la Especificación del lenguaje C#.

Para obtener información sobre los campos ref, consulte la sección de los campos ref del artículo de los tipos de refestructura.

Referencia con ámbito

La palabra clave contextual scoped restringe la duración de un valor. El modificador scoped restringe la duración ref-safe-to-escape o safe-to-escape, respectivamente, al método actual. De hecho, al agregar el modificador scoped se afirma que el código no extenderá la duración de la variable.

Puede aplicar scoped a un parámetro o variable local. El modificador scoped se puede aplicar a parámetros y variables locales cuando el tipo es ref struct. De lo contrario, el modificador scoped solo se puede aplicar a las variables de referencia locales. Esto incluye las variables locales declaradas con el modificador ref y los parámetros declarados con los modificadores in, ref o out.

El modificador scoped se agrega implícitamente a this en los métodos declarados en struct y en parámetros out y ref cuando el tipo es ref struct.

Especificación del lenguaje C#

Para más información, vea las secciones siguientes de la Especificación del lenguaje C#:

Para obtener más información sobre el modificador scoped, consulte la nota de propuesta de mejoras de estructura de bajo nivel.

Consulte también