Menu

Variáveis em C#: var, const, readonly, escopo e nomes

Como declarar e atribuir variáveis em C#, quando var é uma boa ideia e quando não é, como funciona o escopo, a diferença entre const, readonly e static readonly, as convenções de nomes e o erro de variável não atribuída.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Uma variável é um local de armazenamento com nome e com tipo fixo. Em C# você a declara com um tipo e um nome, e opcionalmente dá a ela um valor na mesma instrução. O tipo nunca muda depois: uma variável int guarda números inteiros enquanto existir.

Saída:

Priya bought 5 items for 20.25
10

Atribuir um valor do tipo errado é um erro de compilação: quantity = "five"; falha com CS0029 (cannot implicitly convert type 'string' to 'int'). Converter entre tipos é explícito; veja conversão de tipos.

var: deixando o compilador inferir o tipo

var declara uma variável local cujo tipo é inferido a partir do inicializador. Não é tipagem dinâmica: o tipo é fixado em tempo de compilação, exatamente como se você o tivesse escrito.

Saída:

String
Int32
Decimal
Double
List`1

var tem três regras. Só funciona para variáveis locais (não para campos nem parâmetros). A variável precisa ser inicializada na declaração: var x; é o erro CS0818, "Implicitly-typed variables must be initialized". E o inicializador precisa ter um tipo: var nothing = null; não compila, porque null sozinho não tem tipo.

Quando usá-lo é uma questão de estilo da equipe. A orientação usual é usar var quando o tipo é óbvio pelo lado direito, e escrever o tipo quando não é:

var orders = new List<Order>();         // obvious: var is fine
var reader = new StreamReader(path);    // obvious
decimal discount = CalculateDiscount(); // not obvious: name the type
int count = items.Count();              // makes the intent clear

Uma armadilha sutil: var total = 0; faz de total um int, então somar 2.5 a ele depois falha, e var price = 10; é um int, não um decimal. Quando o tipo do literal não é o que você quer, escreva o tipo ou adicione um sufixo (10m, 0.0).

Escopo

Uma variável local existe da declaração até o fim do bloco { } em que foi declarada. Variáveis declaradas no cabeçalho de um laço ou no corpo de um if não ficam visíveis depois dele.

Saída:

high
240

Ao contrário de C e C++, C# não permite que um bloco interno declare uma variável local com o mesmo nome de uma do bloco que o contém (erro CS0136): o nome precisa significar uma coisa só ao longo do método. Dois blocos irmãos podem reutilizar um nome, como fazem dois laços for separados que declaram i cada um.

Atribuição definida

Variáveis locais não têm valor padrão. O compilador acompanha todos os caminhos do método e se recusa a compilar se uma variável puder ser lida antes de ser atribuída:

int discount;
if (isMember)
{
    discount = 10;
}
Console.WriteLine(discount);
// error CS0165: Use of unassigned local variable 'discount'

Resolva inicializando na declaração (int discount = 0;) ou atribuindo em todos os ramos (adicione um else). Campos e elementos de array são diferentes: eles recebem automaticamente o valor padrão do seu tipo (0, false, null).

const: constantes de tempo de compilação

Uma const é um valor fixado em tempo de compilação. Ela precisa ser inicializada com uma expressão constante (um literal, outra const ou aritmética entre elas), e só pode ser um número, char, bool, string, enum ou null.

Saída:

Price in EUR
120.00 EUR
350

Um campo const é implicitamente static, então é acessado pelo nome do tipo (Pricing.VatRate), e escrever static const é um erro. O compilador copia o valor para todo lugar que o usa, e é por isso que consts não custam nada em tempo de execução, e também por isso uma const pública em uma biblioteca deve ser um valor que nunca vai mudar (como o número de dias de uma semana).

readonly e static readonly

Um campo readonly só pode ser atribuído na declaração ou em um construtor da sua classe. Depois da construção, ele não pode mudar. Ao contrário de const, o valor é calculado em tempo de execução, pode ser de qualquer tipo e pode variar entre objetos.

Saída:

ACC-17 opened 2024-05-02
Launch: 2020-01-15
basic, pro

As últimas linhas mostram o mal-entendido comum: readonly protege o campo, não o objeto para o qual ele aponta. Plans sempre vai se referir ao mesmo array, mas os elementos do array ainda podem mudar. Para coleções realmente imutáveis, use ReadOnlyCollection<T> ou ImmutableArray<T>.

Resumo dos três:

constreadonlystatic readonly
Valor conhecidoEm tempo de compilaçãoEm tempo de execuçãoEm tempo de execução
Tipos permitidosNúmeros, char, bool, string, enums, nullQualquerQualquer
Definido emSó na declaraçãoDeclaração ou construtorDeclaração ou construtor static
Por objeto ou compartilhadoCompartilhado (implicitamente static)Por objetoCompartilhado
Variáveis locaisSim (const int x = 1;)NãoNão

Convenções de nomes

Nomes em C# diferenciam maiúsculas de minúsculas (total e Total são variáveis diferentes) e precisam começar com uma letra ou um sublinhado. As convenções da Microsoft, seguidas por quase todo código C#:

  • Variáveis locais e parâmetros: camelCase (orderCount, unitPrice).
  • Constantes, propriedades, métodos, classes e campos públicos: PascalCase (MaxItems, VatRate).
  • Campos privados: _camelCase com sublinhado no início (_balance), uma convenção muito difundida em código .NET.
  • Booleanos se leem como perguntas: isActive, hasDiscount, canRetry.
  • Evite abreviações e prefixos húngaros (strName, iCount).

Uma palavra-chave de C# não pode ser um nome, a menos que você a prefixe com @: var @class = "5B"; é válido, o que às vezes é útil em código gerado ou em nomes de campos JSON.

Trocando valores e atribuição múltipla

Desde o C# 7, as tuplas permitem atribuir várias variáveis em uma instrução, o que dá uma troca em uma linha:

Saída:

20 10
Lisbon: 545,000

A segunda forma é a desconstrução: ela declara city como string e population como int a partir de uma tupla. Mais em tuplas.

Perguntas frequentes

O que é var em C#?

var diz ao compilador para inferir o tipo de uma variável local a partir do valor com que ela é inicializada: var count = 5; declara um int. A variável continua com tipagem estática e não pode guardar uma string depois. var só funciona para variáveis locais inicializadas na mesma instrução.

Qual a diferença entre const e readonly em C#?

Uma const é uma constante de tempo de compilação: o valor precisa ser conhecido na compilação (números, strings, bool, null), ela é implicitamente static e o valor é copiado para todo lugar que a usa. Um campo readonly é definido uma vez em tempo de execução, na declaração ou em um construtor, pode ser de qualquer tipo e pode variar de objeto para objeto.

Quando usar static readonly em vez de const?

Use static readonly para um valor compartilhado que não pode ser uma constante de tempo de compilação, como um DateTime, um array ou um objeto, ou para um valor público que pode mudar entre versões de uma biblioteca. Como os valores const são copiados para os assemblies que os usam, mudar uma const pública exige recompilar todos os assemblies que a usam.

O que significa "use of unassigned local variable" em C#?

Erro CS0165: o compilador encontrou um caminho em que uma variável local é lida antes de receber algum valor. Variáveis locais não têm valor padrão em C#. Inicialize a variável ao declará-la, ou garanta que todo ramo do if/switch a atribua antes de ela ser usada.

Devo usar var ou tipos explícitos em C#?

As duas formas estão certas; cada equipe escolhe um estilo. Uma regra comum é usar var quando o tipo é óbvio pelo lado direito (var list = new List<string>();) e escrever o tipo quando não é (decimal total = GetTotal();). O código do próprio runtime do .NET segue mais ou menos essa regra.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR