Instruções de declaração

Uma instrução de declaração declara uma nova variável local, constante local ou variável de referência local. Para declarar uma variável local, especifique seu tipo e forneça seu nome. Você pode declarar várias variáveis do mesmo tipo em uma instrução, como mostra o seguinte exemplo:

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

Em uma instrução de declaração, você também pode inicializar uma variável com seu valor inicial:

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

Os exemplos anteriores especificam explicitamente o tipo de uma variável. Você também pode deixar o compilador inferir o tipo de uma variável de sua expressão de inicialização. Para fazer isso, use a palavra-chave var em vez do nome de um tipo. Para saber mais, confira a seção Variáveis locais de tipo implícito.

Para declarar uma constante local, use a palavra-chave const, como mostra o seguinte exemplo:

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

Ao declarar uma constante local, você também deve inicializá-la.

Para obter informações sobre variáveis de referência local, confira a seção Variáveis de referência.

Variáveis locais tipadas implicitamente

Ao declarar uma variável local, você pode deixar o compilador inferir o tipo da variável da expressão de inicialização. Para fazer isso, use a palavra-chave var em vez do nome de um 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 mostra o exemplo anterior, variáveis locais de tipo implícito são fortemente tipadas.

Observação

Quando você usa var no contexto com reconhecimento anulável habilitado e o tipo de uma expressão de inicialização é um tipo de referência, o compilador sempre infere um tipo de referência anulável mesmo que o tipo de uma expressão de inicialização não seja anulável.

Um uso comum de var é com uma expressão de invocação de construtor. O uso de var permite não repetir um nome de tipo em uma declaração de variável e instanciação de objeto, como mostra o exemplo a seguir:

var xs = new List<int>();

Você pode usar uma expressão new com tipo de destino como alternativa:

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

Ao trabalhar com tipos anônimos, você deve usar variáveis locais tipadas implicitamente. O exemplo a seguir mostra uma expressão de consulta que usa um tipo anônimo para conter o nome e o número de telefone de um 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}");
}

No exemplo anterior, você não pode especificar explicitamente o tipo da variável fromPhoenix. O tipo é IEnumerable<T>, mas nesse caso T é um tipo anônimo e você não pode fornecer seu nome. É por isso que você precisa usar var. Pelo mesmo motivo, você deve usar var ao declarar a variável de iteração customer na instrução foreach.

Para obter mais informações sobre variáveis locais tipadas implicitamente, confira Variáveis locais tipadas implicitamente.

Na correspondência de padrões, a palavra-chave var é usada em um var padrão.

Variáveis de referência

Ao declarar uma variável local e adicionar a palavra-chave ref antes do tipo da variável, você declara uma variável de referência ou um local ref:

ref int aliasOfvariable = ref variable;

Uma variável de referência é uma variável que se refere a outra variável, que é chamada de referenciante. Ou seja, uma variável de referência é um alias para seu referenciante. Quando você atribui um valor a uma variável de referência, esse valor é atribuído ao referenciador. Quando você lê o valor de uma variável de referência, o valor do referenciante é retornado. O exemplo a seguir demonstra esse comportamento:

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

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

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

Use o ref operador de atribuição= ref para alterar o referenciante de uma variável de referência, como mostra o exemplo a seguir:

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

No exemplo anterior, a variável de referência element é inicializada como um alias para o primeiro elemento de matriz. Ela é reatribuída ref para fazer referência ao último elemento de matriz.

Você pode definir uma variável local ref readonly. Você não pode atribuir um valor a uma variável ref readonly. No entanto, você pode reatribuir ref essa variável de referência, como mostra o exemplo a seguir:

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

Você pode atribuir um retorno de referência a uma variável de referência, como mostra o exemplo a seguir:

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

No exemplo anterior, o método GetReferenceToMax é um método returns-by-ref. Ele não retorna o valor máximo em si, mas um retorno de referência que é um alias para o elemento de matriz que contém o valor máximo. O método Run atribui um retorno de referência à variável de referência max. Em seguida, atribuindo a max, ele atualiza o armazenamento interno da instância store. Você também pode definir um método ref readonly. Os chamadores de um método ref readonly não podem atribuir um valor ao seu retorno de referência.

A variável de iteração da instrução foreach pode ser uma variável de referência. Para obter mais informações, consulte a seção sobre a instrução foreach do artigo Instruções de iteração.

Em cenários críticos de desempenho, o uso de variáveis de referência e retornos pode aumentar o desempenho evitando operações de cópia potencialmente caras.

O compilador garante que uma variável de referência não sobreviva ao seu referenciador e permaneça válida durante todo o tempo de vida. Para saber mais, confira a seção Contextos seguros de referência da Especificação da linguagem C#.

Para obter informações sobre os campos ref, confira a seção refcampos do artigo reftipos de estrutura.

ref com escopo

A palavra-chave contextual scoped restringe o tempo de vida de um valor. O modificador scoped restringe o tempo de vida ref-safe-to-escape ou safe-to-escape, respectivamente, ao método atual. Efetivamente, adicionar o modificador scoped declara que seu código não estenderá o tempo de vida da variável.

Você pode aplicar scoped a um parâmetro ou variável local. O modificador scoped pode ser aplicado a parâmetros e locais quando o tipo for um ref struct. Caso contrário, o modificador scoped poderá ser aplicado somente a variáveis de referência locais. Isso inclui variáveis locais declaradas com o modificador ref e os parâmetros declarados com os modificadores in, ref ou out.

O modificador scoped é adicionado implicitamente a this em métodos declarados em parâmetros struct, out e ref quando o tipo for um ref struct.

Especificação da linguagem C#

Para obter mais informações, confira as seguintes seções da especificação da linguagem C#:

Para obter mais informações sobre o modificador scoped, consulte a nota de proposta Aprimoramentos de struct de baixo nível.

Confira também