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
-
Imutabilidade:
- Por padrão, um
record structé imutável, o que significa que as propriedades definidas nele sãoinit-only(somente inicializáveis no construtor ou inicializador de objetos).
- Por padrão, um
-
Igualdade baseada em valor:
- A comparação entre dois
record structsconsidera 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.
- A comparação entre dois
-
Sem alocação de heap:
- Como é um
struct, orecord structé alocado na stack (pilha), tornando-o mais eficiente em termos de desempenho em muitos casos, especialmente para objetos pequenos.
- Como é um
-
Facilidade de uso:
- Ele herda a sintaxe simplificada e funcionalidade dos
records, como construtores automáticos e desestruturação.
- Ele herda a sintaxe simplificada e funcionalidade dos
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
CurrencyouUnit.
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
-
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 umstructou umaclass.
- Embora seja possível criar propriedades mutáveis em um
-
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.
- 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
-
Se a Identidade do Objeto é Importante:
- Se o tipo precisa ser referenciado por identidade, um
record structnão é adequado, pois structs são passados por valor, não por referência.
- Se o tipo precisa ser referenciado por identidade, um
Comparação: record struct vs record class
| Aspecto | record struct | record class |
|---|---|---|
| Alocação | Stack (pilha) | Heap (amontoado) |
| Mutabilidade padrão | Imutável | Imutável |
| Igualdade | Baseada em valor | Baseada em valor |
| Cópia | Por valor | Por referência |
| Uso recomendado | Tipos pequenos e transitórios | Tipos 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.