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.
- Criar uma constante com
conste 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
constereadonly.
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 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
staticem 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.PIeint.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.
const | readonly | |
|---|---|---|
| Quando o valor é decidido | Na compilação | Quando o programa roda (na criação do objeto) |
| Tipos | Números, char, bool, string, enums | Qualquer tipo |
Pode vir de uma conta com variáveis, de DateTime.Now, do teclado? | Não | Sim |
| Onde | Dentro do programa (local) ou numa classe | Só numa classe (é um campo) |
| Exemplo | const 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
| Escrita | O 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.MaxValue | Constantes do .NET |
readonly | Trancado na execução; aceita qualquer tipo (só em classes) |
Exercícios
1. A palavra que tranca
Complete para criar uma constante:
2. O nome no padrão do .NET
Escreva o nome taxa de juros em PascalCase, sem acento:
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
constcria 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,stringe enums podem serconst(CS0283), e nunca comvar(CS0822). - Constantes de uma classe:
public const, usadas comoRegras.IdadeMinima. Para valores decididos na execução,readonly.