Dois pontos de interrogação em C#: não é um erro, mas uma ferramenta poderosa
\n\nImagine: você está escrevendo código em C# e de repente vê a construção ??. O primeiro pensamento — um erro de digitação? Um caractere extra? Na verdade, este é um dos operadores mais elegantes e úteis da linguagem — o null-coalescing (operador de coalescência nula). Se você já pegou um NullReferenceException e amaldiçoou tudo neste mundo — este operador se tornará seu salva-vidas.
Neste artigo, vamos entender o que significam dois pontos de interrogação em C#, como usá-los corretamente, como eles diferem do operador ternário e mostrar exemplos reais da prática. Vamos lá!
\n\nO que é o operador ?? em C#?
\n\nO operador ?? (dois pontos de interrogação) é um operador binário que retorna o operando esquerdo se ele não for null; caso contrário, retorna o operando direito. Simplificando: "Se o da esquerda não for null — pegue o da esquerda, senão pegue o da direita".
A sintaxe é extremamente simples:
\n\nvar resultado = esquerda ?? direita;\n\nOnde:
\n- \n
esquerda— valor que pode ser null; \n direita— valor padrão (não pode ser null se o tipo da direita for nullable). \n
Primeiro exemplo: salvando-se do null
\n\nSuponha que você tenha uma variável string? nome (string nullable). Você quer exibir o nome do usuário e, se não houver, "Convidado":
string? nome = ObterNomeUsuario(); // pode retornar null\nstring nomeExibicao = nome ?? "Convidado";\nConsole.WriteLine(nomeExibicao);\n\nSem o operador ??, você teria que escrever:
string nomeExibicao = (nome != null) ? nome : "Convidado";\n\nConcorda que a primeira opção se lê como uma frase normal: "nome ou convidado". Bonito, não é?
\n\nOperador ??=: a nova geração do null-coalescing
\n\nA partir do C# 8.0, surgiu o operador ??= — uma forma abreviada de atribuição com null-coalescing. Ele atribui o valor do operando direito ao esquerdo, apenas se o operando esquerdo for igual a null.
Sintaxe:
\n\nesquerda ??= direita;\n\nIsso é equivalente a:
\n\nif (esquerda == null) esquerda = direita;\n\nExemplo com ??=
\n\nList<int>? numeros = null;\nnumeros ??= new List<int>(); // numeros agora = new List<int>()\nnumeros.Add(42);\nConsole.WriteLine(numeros.Count); // 1\n\nObserve: se numeros já estivesse inicializado (não null), a atribuição não ocorreria. Isso é ideal para inicialização preguiçosa.
Comparação com o operador ternário (? :)
\n\nMuitos iniciantes confundem ?? com o operador ternário ? :. Vamos esclarecer de uma vez por todas:
- \n
- Operador ternário — é uma forma abreviada de if-else. Ele verifica QUALQUER condição booleana:
condição ? valor_se_true : valor_se_false. \n - Operador ?? — verifica APENAS se é null. É um caso específico, otimizado para uma única tarefa. \n
Exemplo de operador ternário:
\n\nint idade = 18;\nstring status = (idade >= 18) ? "Adulto" : "Menor de idade";\n\nAgora, o que acontece se tentarmos substituir ?? pelo ternário:
string? nome = null;\nstring nomeExibicao = nome != null ? nome : "Convidado"; // funciona, mas é mais longo\nstring nomeExibicao2 = nome ?? "Convidado"; // mais curto e mais claro\n\nConclusão: use ?? quando precisar simplesmente substituir um valor padrão no lugar de null. Para todas as outras condições, use o operador ternário.
Encadeamento de operadores ??
\n\nVocê pode encadear vários operadores ?? em sequência. Isso é útil quando há várias fontes possíveis de valor:
string? primeiraOpcao = ObterDoCache