Ferramentas gratuitas para desenvolvedores. Nenhum dado real de pessoas é consultado ou armazenado.Como funciona o algoritmo do CPF →
C#

Validar, gerar e formatar CPF em C#

Classe estática em C# 12 (.NET 8) para validar, gerar e formatar CPF com o módulo 11, testes com xUnit [Theory] e chamada à API com HttpClient.

Roberto GuerraPublicado em 05 de outubro de 2026Editar no GitHub

Validar CPF em C# costuma aparecer em APIs ASP.NET Core, em validadores do FluentValidation e em rotinas de importação. A classe abaixo é estática, não guarda estado e usa só a biblioteca base do .NET 8, com a sintaxe do C# 12. Ela supõe um projeto com ImplicitUsings habilitado, o padrão dos templates atuais, que já importa System e System.Linq. A lógica é a mesma das ferramentas do site; o guia do algoritmo do módulo 11 detalha a conta.

Validar CPF em C#

Cpf.cs
using System.Security.Cryptography;
using System.Text.RegularExpressions;

namespace CpfDev;

public static class Cpf
{
  private static readonly Regex Separadores = new(@"[.\-\s]", RegexOptions.Compiled);

  private static int CalcularDigito(string digitos, int pesoInicial)
  {
      var soma = 0;
      for (var i = 0; i < digitos.Length; i++)
      {
          soma += (digitos[i] - '0') * (pesoInicial - i);
      }
      var resto = soma % 11;
      return resto < 2 ? 0 : 11 - resto;
  }

  public static bool Validar(string? valor)
  {
      if (valor is null) return false;
      var cpf = Separadores.Replace(valor, "");
      if (cpf.Length != 11 || !cpf.All(char.IsAsciiDigit)) return false;
      if (cpf.All(c => c == cpf[0])) return false;
      var dv1 = CalcularDigito(cpf[..9], 10);
      var dv2 = CalcularDigito(cpf[..10], 11);
      return cpf[9] - '0' == dv1 && cpf[10] - '0' == dv2;
  }
}

Detalhes da implementação:

  • char.IsAsciiDigit (.NET 7 em diante) aceita só 0 a 9. char.IsDigit aceitaria dígitos de outros alfabetos, que quebrariam a conta com - '0'.
  • cpf.All(c => c == cpf[0]) recusa 111.111.111-11 e as outras sequências repetidas, que fecham o módulo 11, mas não são consideradas válidas.
  • cpf[..9] usa o operador de intervalo para pegar a base sem Substring.
  • string? deixa explícito, com nullable reference types, que a função aceita null e devolve false.

Com 529.982.247-25, a primeira soma é 295 (resto 9, dígito 2) e a segunda é 347 (resto 6, dígito 5); as comparações batem e Validar devolve true. Com 529.982.247-26, cpf[10] - '0' vale 6 e o dígito calculado é 5, então o resultado é false.

No FluentValidation, a regra fica RuleFor(x => x.Cpf).Must(Cpf.Validar).WithMessage("CPF inválido").

Gerar CPF válido em C#

Os métodos a seguir ficam dentro da mesma classe. RandomNumberGenerator.GetInt32 usa o gerador criptográfico do sistema.

Cpf.cs
    public static string Gerar(bool formatado = false)
  {
      string base9;
      do
      {
          base9 = string.Concat(Enumerable.Range(0, 9).Select(_ => RandomNumberGenerator.GetInt32(10)));
      } while (base9.All(c => c == base9[0]));
      var dv1 = CalcularDigito(base9, 10);
      var dv2 = CalcularDigito(base9 + dv1, 11);
      var cpf = $"{base9}{dv1}{dv2}";
      return formatado ? Formatar(cpf) : cpf;
  }

A variável se chama base9 porque base é palavra reservada em C#. O CPF gerado é válido, mas pode coincidir com um CPF real por acaso; use-o em testes, seeds do Entity Framework e ambientes de homologação. O guia de massa de teste e LGPD explica os cuidados.

Formatar e limpar CPF em C#

Cpf.cs
    public static string Limpar(string? valor) =>
      valor is null ? "" : new string(valor.Where(char.IsAsciiDigit).ToArray());

  public static string Formatar(string? valor)
  {
      var d = Limpar(valor);
      if (d.Length != 11)
          throw new ArgumentException($"CPF precisa de 11 dígitos, recebeu {d.Length}", nameof(valor));
      return $"{d[..3]}.{d[3..6]}.{d[6..9]}-{d[9..]}";
  }

Cpf.Formatar("52998224725") devolve "529.982.247-25", e Cpf.Limpar("529.982.247-25") devolve "52998224725". Grave a versão limpa em uma coluna char(11); o guia sobre validar CPF no banco de dados explica por que tipos numéricos perdem o zero à esquerda.

Testes

No xUnit, [Theory] com um [InlineData] por caso gera um teste para cada linha.

CpfTests.cs
using CpfDev;
using Xunit;

public class CpfTests
{
  [Theory]
  [InlineData("529.982.247-25", true)]
  [InlineData("111.111.111-11", false)]
  [InlineData("529.982.247-26", false)]
  public void Validar_DevolveOResultadoEsperado(string cpf, bool esperado)
  {
      Assert.Equal(esperado, Cpf.Validar(cpf));
  }
}

Rode com dotnet test. Para mais entradas problemáticas, como CPF com letras ou com 10 dígitos, veja os erros comuns ao validar CPF.

Usar a API em vez de reimplementar

A API do cpf.dev.br valida e gera CPFs por HTTP, sem chave, com limite de 60 requisições por minuto por IP. GetFromJsonAsync desserializa a resposta direto para um record.

Program.cs
using System.Net.Http.Json;

using var http = new HttpClient { BaseAddress = new Uri("https://www.cpf.dev.br/") };

var r = await http.GetFromJsonAsync<RespostaValidacao>("api/v1/cpf/validar/529.982.247-25");
Console.WriteLine(r);
// RespostaValidacao { Valido = True, Cpf = 52998224725, Formatado = 529.982.247-25, Uf = System.String[] }

var lote = await http.GetFromJsonAsync<RespostaLote>("api/v1/cpf/gerar?quantidade=5&uf=SP&formatado=true");
Console.WriteLine(string.Join(", ", lote!.Cpfs));

public record RespostaValidacao(bool Valido, string Cpf, string Formatado, string[] Uf);
public record RespostaLote(string[] Cpfs);

O exemplo cria um HttpClient direto para ficar curto; em ASP.NET Core, registre-o com IHttpClientFactory. A resposta da validação traz Uf igual a ["ES", "RJ"] para esse CPF. Para formulários, a classe local continua sendo a melhor opção. Para conferir um número à mão, use o validador de CPF.

Leia também