C# Constantes

Algumas informações de um programa nunca mudam enquanto ele roda: a taxa de entrega da lojinha, a idade mínima para comprar um ingresso, quantos dias tem a semana. Para elas, o C# tem a constante: uma caixa com nome, como a variável, mas com o valor trancado. Nesta aula você vai criar constantes com const, ver o erro que aparece quando alguém tenta mudá-las e entender por que elas deixam o código mais fácil de ler e de manter.

Você vai aprender
  • Criar uma constante com const e por que o nome vai em PascalCase (TaxaEntrega).
  • O erro de tentar mudar uma constante (CS0131) e o de esquecer o valor (CS0145).
  • Por que trocar "números mágicos" por constantes.
  • Constantes feitas de contas e de textos, até com interpolação C# 10.
  • O que pode e o que não pode ser const (CS0133, CS0283, CS0822).
  • Constantes numa classe, e a diferença entre const e readonly.

Todos os programas desta aula foram rodados com o .NET 10 (C# 14) na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/cs, com dotnet run arquivo.cs.


A ideia: a placa pintada na parede

Na lojinha da Ana há um quadro-negro com a promoção do dia, que ela apaga e reescreve toda manhã: isso é uma variável. E há uma placa pintada na parede: "Lojinha da Ana, desde 2020". Ninguém apaga a placa. Para mudá-la, é preciso repintar a loja: isso é uma constante.

No C#, "repintar" quer dizer mudar o código e compilar de novo. Enquanto o programa roda, o valor de uma constante é sempre o mesmo, e o compilador garante isso.


1. Criando constantes com const

const decimal TaxaEntrega = 7.50m;
const int DiasNaSemana = 7;
const string NomeDaLoja = "Lojinha da Ana";

decimal compra = 42.00m;
Console.WriteLine(NomeDaLoja);
Console.WriteLine($"Compra: {compra}");
Console.WriteLine($"Entrega: {TaxaEntrega}");
Console.WriteLine($"Total: {compra + TaxaEntrega}");
Console.WriteLine($"Entregamos {DiasNaSemana} dias por semana");
$ dotnet run const1.cs
Lojinha da Ana
Compra: 42,00
Entrega: 7,50
Total: 49,50
Entregamos 7 dias por semana
const
Abreviação de constant, "constante". Vem antes do tipo e diz: "este valor nunca muda".
decimal TaxaEntrega = 7.50m;
O resto é igual a uma variável: tipo, nome e valor. O valor é obrigatório e tem de estar ali, na mesma linha.
TaxaEntrega · DiasNaSemana · NomeDaLoja
Os nomes das constantes vão em PascalCase: cada palavra começa com maiúscula, inclusive a primeira. É a convenção do .NET (em C e Java, se usa TAXA_ENTREGA, todo em maiúsculas; no C# isso funciona, mas foge do padrão). Veja Nomes e Convenções.
compra + TaxaEntrega
Uma constante se usa como qualquer variável: em contas, em textos, no Console.WriteLine.

Tentar mudar uma constante

const decimal TaxaEntrega = 7.50m;
TaxaEntrega = 9.90m;
Console.WriteLine(TaxaEntrega);
$ dotnet run consterro1.cs
/home/ana/cs/consterro1.cs(2,1): error CS0131: O lado esquerdo de uma atribuição deve ser uma variável, uma propriedade ou um indexador

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O = guarda o valor da direita na caixa da esquerda (aula Operadores de Atribuição). Só que TaxaEntrega não é uma caixa que aceita valores novos: é uma constante. O erro diz que, à esquerda do =, só pode haver uma variável (ou uma propriedade, ou um indexador, que você verá mais adiante). Em inglês: The left-hand side of an assignment must be a variable, property or indexer. Para a taxa mudar, mude a linha do const.

Esquecer o valor

const int Limite;
Console.WriteLine(Limite);
$ dotnet run consterro2.cs
/home/ana/cs/consterro2.cs(1,11): error CS0145: O campo const requer um valor a ser fornecido

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

Uma variável pode nascer vazia e ganhar valor depois. Uma constante, não: como ela nunca muda, o único momento de dar o valor é na criação. Em inglês: A const field requires a value to be provided.


2. Por que usar constantes: o fim dos números mágicos

Olhe esta linha, escrita há meses por outra pessoa:

decimal salario = 3000m;
decimal desconto = salario * 0.075m;
Console.WriteLine(desconto);
$ dotnet run magico.cs
225,000

O que é 0.075? Um imposto? Uma taxa do banco? Um número solto no meio do código, sem explicação, é chamado de número mágico: funciona, mas ninguém sabe por quê. Com uma constante, o nome explica:

const decimal AliquotaInss = 0.075m;
decimal desconto = salario * AliquotaInss;

E há uma segunda vantagem: quando a alíquota mudar, você muda uma linha, em vez de procurar todos os 0.075m do programa (e torcer para não esquecer nenhum, nem trocar sem querer um 0.075m que era outra coisa). A missão final desta aula é exatamente isso.

Quando criar uma constante

Quando o valor tem um significado (taxa, limite, nome da loja) e é o mesmo durante todo o programa. Números óbvios, como o 2 de "dividir por 2" ou o 0 de "começar do zero", não precisam de nome.


3. Constantes feitas de contas e de textos

O valor de uma constante pode ser uma conta, desde que ela só use outras constantes. O compilador faz a conta na hora de compilar:

const int SegundosPorMinuto = 60;
const int SegundosPorHora = SegundosPorMinuto * 60;
const int SegundosPorDia = SegundosPorHora * 24;
const string Loja = "Lojinha";
const string Saudacao = $"Bem-vindo à {Loja}!";
const string Rodape = Loja + " - desde 2020";
Console.WriteLine(SegundosPorDia);
Console.WriteLine(Saudacao);
Console.WriteLine(Rodape);
Console.WriteLine(Math.PI);
Console.WriteLine(int.MaxValue);
$ dotnet run constexpr.cs
86400
Bem-vindo à Lojinha!
Lojinha - desde 2020
3,141592653589793
2147483647
SegundosPorMinuto * 60 · SegundosPorHora * 24
Contas só com constantes e números fixos: valem. SegundosPorDia é 86 400, calculado pelo compilador.
$"Bem-vindo à {Loja}!"
Uma string interpolada também pode ser constante C# 10, se tudo dentro das chaves for uma constante string.
Loja + " - desde 2020"
Juntar strings constantes com + também vale.
Math.PI · int.MaxValue
O próprio .NET está cheio de constantes: Math.PI (o π, aula Matemática), int.MaxValue (aula Inteiros).

Como o compilador faz essas contas, ele também confere os limites: const int MaisUm = int.MaxValue + 1; dá o erro CS0220 (estouro na compilação), e uma divisão por uma constante que vale zero dá CS0020: Divisão por zero constante.

A conta tem de ser só de constantes

int minutos = 60;
const int SegundosPorHora = minutos * 60;
Console.WriteLine(SegundosPorHora);
$ dotnet run consterro3.cs
/home/ana/cs/consterro3.cs(2,29): error CS0133: A expressão que está sendo atribuída a "SegundosPorHora" deve ser constante

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

minutos é uma variável: o compilador não pode confiar no valor dela, porque ela poderia mudar. Em inglês: The expression being assigned to 'SegundosPorHora' must be constant. O mesmo erro aparece com qualquer coisa que só se conhece com o programa rodando: o que o usuário digitou, a data de hoje, o tamanho de um arquivo.

Missão: o programa não compila (CS0133), porque a constante usa uma variável. Transforme a variável em constante: const int SegundosPorMinuto = 60; (repare no nome em PascalCase; troque também o nome na segunda linha) para mostrar 3600.

int segundosPorMinuto = 60;
const int SegundosPorHora = segundosPorMinuto * 60;
Console.WriteLine(SegundosPorHora);
const int SegundosPorMinuto = 60;
const int SegundosPorHora = SegundosPorMinuto * 60;
Console.WriteLine(SegundosPorHora);

4. O que pode ser const

Só tipos cujo valor o compilador sabe escrever direto no programa: os números (int, long, double, decimal…), char, bool, string e os enums. Uma data, por exemplo, não pode:

const DateTime Inauguracao = new DateTime(2020, 3, 1);
Console.WriteLine(Inauguracao);
$ dotnet run consterro4.cs
/home/ana/cs/consterro4.cs(1,7): error CS0283: O tipo "DateTime" não pode ser declarado const

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

Um array também não (const int[] Notas = { 7, 8, 9 }; dá CS0133, porque um array é criado com o programa rodando). Para esses casos existe o readonly (seção 6).

E const não combina com var: o tipo de uma constante tem de ser escrito.

const var Pi = 3.14;
Console.WriteLine(Pi);
$ dotnet run consterro6.cs
/home/ana/cs/consterro6.cs(1,7): error CS0822: Variáveis de tipo implícito não podem ser constantes

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

5. Constantes numa classe

Até aqui as constantes estavam soltas no programa: são constantes locais, que só existem naquele trecho. Quando várias partes do programa usam a mesma regra, o costume é guardá-las numa classe, com public para todo mundo enxergar:

Console.WriteLine(Regras.IdadeMinima);
Console.WriteLine(Regras.Desconto);
decimal preco = 100m;
Console.WriteLine(preco - preco * Regras.Desconto);

static class Regras
{
    public const int IdadeMinima = 18;
    public const decimal Desconto = 0.10m;
}
$ dotnet run constclasse.cs
18
0,10
90,00
static class Regras { … }
Uma classe que só serve de "caixa de regras". As classes começam em Classes e Objetos, e o static em static. Num arquivo com instruções soltas, as classes ficam no fim.
public const int IdadeMinima = 18;
public ("público") deixa a constante visível fora da classe (aula public, private e internal).
Regras.IdadeMinima
Fora da classe, a constante é chamada pelo nome da classe, um ponto e o nome dela. É o mesmo jeito de Math.PI e int.MaxValue.

6. const × readonly

O readonly ("somente leitura") também tranca um valor, mas de um jeito diferente: o valor é decidido quando o programa roda, e depois não muda mais. Por isso ele aceita datas, arrays e valores calculados.

constreadonly
Quando o valor é decididoNa compilaçãoQuando o programa roda (na criação do objeto)
TiposNúmeros, char, bool, string, enumsQualquer tipo
Pode vir de uma conta com variáveis, de DateTime.Now, do teclado?NãoSim
OndeDentro do programa (local) ou numa classeSó numa classe (é um campo)
Exemploconst int DiasNaSemana = 7;readonly DateTime Criada = DateTime.Now;

Regra prática: se o valor é o mesmo para sempre e você sabe escrevê-lo no código, const. Senão, readonly. Os detalhes estão em readonly e init.


Quando dá errado

error CS0131: O lado esquerdo de uma atribuição deve ser uma variável, uma propriedade ou um indexador

O que significa: o programa tenta guardar um valor novo numa constante (TaxaEntrega = 9.90m;).

Como consertar: se o valor muda durante o programa, ele não é constante: tire o const. Se é a regra que mudou, mude o valor na linha do const.

error CS0145: O campo const requer um valor a ser fornecido

O que significa: const int Limite; sem valor.

Como consertar: dê o valor na mesma linha: const int Limite = 10;.

error CS0133: A expressão que está sendo atribuída a "…" deve ser constante

O que significa: o valor da constante usa uma variável, um método, um array ou qualquer coisa que só existe com o programa rodando.

Como consertar: use só constantes e valores fixos na conta, ou troque o const por uma variável comum (ou por readonly, numa classe).

error CS0283: O tipo "DateTime" não pode ser declarado const

O que significa: o tipo não pode ser constante (só números, char, bool, string e enums podem).

Como consertar: use static readonly numa classe: static readonly DateTime Inauguracao = new DateTime(2020, 3, 1);.

error CS0822: Variáveis de tipo implícito não podem ser constantes

O que significa: const var. O var não vale para constantes.

Como consertar: escreva o tipo: const double Pi = 3.14; (ou use o Math.PI, que já existe).

warning CS0219: A variável "Nunca" é atribuída, mas seu valor nunca é usado

O que significa: uma constante local foi criada e nunca usada. É só um aviso: o programa roda (aula Avisos do Compilador).

Como consertar: use a constante onde ela devia estar, ou apague a linha.


Referência rápida

EscritaO que é
const decimal TaxaEntrega = 7.50m;Constante local: tipo escrito, valor obrigatório, nome em PascalCase
const int SegundosPorDia = 60 * 60 * 24;Constante feita de conta (calculada na compilação)
const string Saudacao = $"Olá, {Loja}";Interpolação constante C# 10 (só com constantes string dentro)
public const int IdadeMinima = 18;Constante numa classe; uso: Regras.IdadeMinima
Math.PI, int.MaxValueConstantes do .NET
readonlyTrancado na execução; aceita qualquer tipo (só em classes)

Exercícios

1. A palavra que tranca

Complete para criar uma constante:

int IdadeMinima = 18;

2. O nome no padrão do .NET

Escreva o nome taxa de juros em PascalCase, sem acento:

const decimal = 0.02m;

3. O erro de mudar

Qual é o código do erro que aparece em Limite = 20;, se Limite é uma constante?

4. Qual destas constantes compila?

5. Por que trocar salario * 0.075m por salario * AliquotaInss?

6. Você precisa guardar, sem mudar depois, a hora em que o programa começou. O que usar?

Missão final: a taxa de entrega subiu

Missão: a taxa de entrega subiu de R$ 7,50 para R$ 9,90, e ela aparece em três lugares. Crie a constante const decimal TaxaEntrega = 9.90m; no começo do programa e use-a nas três linhas, no lugar do 7.50m. A saída deve ser Pedido 1: 51,90, Pedido 2: 28,40 e Pedido 3: 39,90.

decimal pedido1 = 42.00m;
decimal pedido2 = 18.50m;
decimal pedido3 = 30.00m;
Console.WriteLine($"Pedido 1: {pedido1 + 7.50m}");
Console.WriteLine($"Pedido 2: {pedido2 + 7.50m}");
Console.WriteLine($"Pedido 3: {pedido3 + 7.50m}");
const decimal TaxaEntrega = 9.90m;
decimal pedido1 = 42.00m;
decimal pedido2 = 18.50m;
decimal pedido3 = 30.00m;
Console.WriteLine($"Pedido 1: {pedido1 + TaxaEntrega}");
Console.WriteLine($"Pedido 2: {pedido2 + TaxaEntrega}");
Console.WriteLine($"Pedido 3: {pedido3 + TaxaEntrega}");

Da próxima vez que a taxa mudar, basta mudar a primeira linha.


Resumo

  • const cria uma caixa com valor trancado: const decimal TaxaEntrega = 7.50m;. Nome em PascalCase.
  • O valor é obrigatório na criação (CS0145) e nunca muda (CS0131).
  • Constantes acabam com os números mágicos: o nome explica o valor, e uma mudança mexe em uma linha só.
  • O valor pode ser uma conta ou um texto feito só de constantes (inclusive $"…", C# 10); com variáveis, CS0133.
  • Só números, char, bool, string e enums podem ser const (CS0283), e nunca com var (CS0822).
  • Constantes de uma classe: public const, usadas como Regras.IdadeMinima. Para valores decididos na execução, readonly.