Skip to main content

Record struct

  • Record struct

Record struct

using Bluedesk.Shared.Core.Exceptions;

namespace Bluedesk.Shared.Domain.ValueObjects;

public record struct Cnpj
{
public string CnpjSemFormatacao { get; init; }

public Cnpj(string cnpj): this()
{
CnpjSemFormatacao = ObterCnpjSemFormatacao(cnpj);
}

private string ObterCnpjSemFormatacao(string cnpj)
{
if(string.IsNullOrEmpty(cnpj)) return string.Empty;

var cnpjSemFormatacao = cnpj.Replace(".", "")
.Replace("/", "")
.Replace("-", "");

if(cnpjSemFormatacao.Length == 14) return cnpjSemFormatacao;

throw new ValidacaoException("Cnpj não contém 14 dígitos");
}

public static implicit operator Cnpj(string cnpj)
{
return new Cnpj(cnpj);
}

public static implicit operator string(Cnpj cnpj)
{
return cnpj.CnpjSemFormatacao;
}
public override string ToString()
{
return CnpjSemFormatacao;
}
}

Explicação

Características do record struct

  1. Imutabilidade:

    • Por padrão, um record struct é imutável, o que significa que as propriedades definidas nele são init-only (somente inicializáveis no construtor ou inicializador de objetos).
  2. Igualdade baseada em valor:

    • A comparação entre dois record structs considera os valores das propriedades, não as referências ou o local na memória, o que é útil em cenários onde a igualdade lógica é mais importante do que a identidade.
  3. Sem alocação de heap:

    • Como é um struct, o record struct é alocado na stack (pilha), tornando-o mais eficiente em termos de desempenho em muitos casos, especialmente para objetos pequenos.
  4. Facilidade de uso:

    • Ele herda a sintaxe simplificada e funcionalidade dos records, como construtores automáticos e desestruturação.

Quando usar record struct

1. Para Representar Tipos de Dados Pequenos e Imutáveis

Se você precisa de um tipo de dado simples, que seja pequeno, imutável e cuja igualdade seja baseada no valor (não na referência), record struct é ideal. Exemplos:

  • Coordenadas (Point, Vector2, etc.).
  • Valores de domínio como Currency ou Unit.

Exemplo:

public readonly record struct Point(int X, int Y);

class Program
{
static void Main()
{
var p1 = new Point(10, 20);
var p2 = new Point(10, 20);

Console.WriteLine(p1 == p2); // True (comparação baseada em valor)
Console.WriteLine(p1); // "Point { X = 10, Y = 20 }"
}
}

2. Quando a Eficiência da Memória é Importante

Em cenários onde muitos objetos semelhantes são criados e descartados rapidamente, e você quer evitar alocação no heap e pressão no garbage collector, record struct é uma boa escolha.

Exemplo: Dados temporários em cálculos matemáticos, como em gráficos ou física.


3. Substituir class quando não há necessidade de identidade

Se você precisa de comportamento similar a record class (como igualdade baseada em valor), mas não precisa de identidade (uma referência única para cada instância), o record struct é mais eficiente.

Por exemplo, ao modelar valores de uma operação financeira:

public readonly record struct Money(decimal Amount, string Currency);

class Program
{
static void Main()
{
var m1 = new Money(100, "USD");
var m2 = new Money(100, "USD");

Console.WriteLine(m1 == m2); // True
}
}

4. Para Minimizar Alocação Desnecessária no Heap

Se o tipo é pequeno e transitório, e você precisa evitar o custo de alocação no heap, como em jogos, processamento de imagem ou computação científica, o record struct é preferível.


Quando NÃO usar record struct

  1. Se o tipo precisa ser mutável:

    • Embora seja possível criar propriedades mutáveis em um record struct, isso vai contra seu objetivo principal de imutabilidade. Nesse caso, prefira um struct ou uma class.
  2. Para tipos grandes ou complexos:

    • Como structs são alocados na pilha, tipos grandes podem causar problemas de desempenho devido à cópia de dados em vez de referência. Para tipos complexos, prefira record class.
  3. Se a Identidade do Objeto é Importante:

    • Se o tipo precisa ser referenciado por identidade, um record struct não é adequado, pois structs são passados por valor, não por referência.

Comparação: record struct vs record class

Aspectorecord structrecord class
AlocaçãoStack (pilha)Heap (amontoado)
Mutabilidade padrãoImutávelImutável
IgualdadeBaseada em valorBaseada em valor
CópiaPor valorPor referência
Uso recomendadoTipos pequenos e transitóriosTipos complexos e persistentes

Resumo

Use record struct:

  • Para modelar dados imutáveis pequenos (como pontos, vetores, valores monetários).
  • Quando eficiência de memória e desempenho são importantes.
  • Quando você precisa de igualdade baseada em valor sem alocação no heap.

Evite em:

  • Tipos complexos ou grandes.
  • Cenários onde a mutabilidade ou identidade são cruciais.