CodeGym /Cursos /C# SELF /record com corpo expl...

record com corpo explícito e record struct

C# SELF
Nível 19 , Lição 3
Disponível

1. Introdução

A sintaxe posicional do record-classe é bem prática pra casos simples:

public record User(string Nome, int Idade);
Record-classe posicional

Mas às vezes bate aquela vontade de colocar métodos extras no record, propriedades diferentes, mudar modificadores de acesso, botar lógica no construtor (tipo validação ou transformar dados “automaticamente”). Pena que na sintaxe posicional não tem onde enfiar isso! Hora de partir pro corpo explícito se:

  • Tu precisa adicionar métodos, propriedades ou lógica extra no record.
  • Precisa controlar o comportamento das propriedades (setter, getter, init, validação).
  • Quer criar vários construtores diferentes pra inicializar de jeitos diferentes.
  • Precisa adicionar interfaces ou implementar métodos especiais.

Montando um record com corpo

A sintaxe é bem parecida com classe. Tu já viu isso aqui:


public class User
{
    /* ... */
}

Só que agora é record:


public record User
{
    // Propriedades definidas explicitamente
    public string Nome { get; init; }
    public int Idade { get; init; }

    // Lógica extra
    public string GetGreeting()
    {
        return $"Oi, meu nome é {Nome} e eu tenho {Idade} anos!";
    }

    // Construtor customizado
    public User(string nome, int idade)
    {
        Nome = nome;
        if (idade < 0)
            throw new ArgumentException("Idade não pode ser negativa!");
        Idade = idade;
    }
}

Curiosidade: Se tu define tuas propriedades explicitamente, o compilador não cria automaticamente as propriedades da sintaxe posicional. Tudo explícito, tudo sob controle.

Versão mista: sintaxe híbrida

C# deixa tu misturar os dois mundos: tu pode declarar um record posicional e ainda botar um corpo nele:


public record User(string Nome, int Idade)
{
    public string GetGreeting()
    {
        return $"Eu sou {Nome}, tenho {Idade} anos!";
    }
}
Record posicional com corpo e métodos extras

Nesse caso, as propriedades Nome e Idade continuam sendo criadas automaticamente pela sintaxe posicional, e teus métodos extras ficam de boa dentro do corpo.

2. Diferenças dos records normais — nuances do corpo

  • O record explícito te dá controle total sobre construtores, propriedades, métodos.
  • Tu pode implementar interfaces ou botar tua própria lógica de comparação, se precisar de regras mais cabulosas pra identificar o objeto.
  • Diferente do record simples com sintaxe posicional, pra adicionar novas propriedades agora é só declarar elas no corpo do record.

// Erro de iniciante!
public record User(string Nome, int Idade)
{
    public string Nome { get; init; } // ← conflito! Propriedade declarada duas vezes
}

Erros de iniciante: Tem gente que tenta escrever public record User(string Nome, int Idade) e ainda coloca no corpo public string Nome { get; init; }, achando que são variáveis diferentes. Não! Isso vai dar conflito (propriedade duplicada). Ou usa só a sintaxe posicional, ou define tudo explicitamente — não mistura.

Exemplos práticos

A gente tá desenvolvendo um app de console onde o usuário cria pedidos. Imagina que a classe de pedido Order era assim:

public record Order(string Produto, int Quantidade, double Preco);

Agora, digamos que a gente precisa validar a quantidade (quantidade não pode ser menor que 1) e adicionar uma propriedade de total:


public record Order
{
    public string Produto { get; init; }
    public int Quantidade { get; init; }
    public double Preco { get; init; }
    public double CustoTotal => Quantidade * Preco;

    public Order(string produto, int quantidade, double preco)
    {
        Produto = produto ?? throw new ArgumentNullException(nameof(produto));
        if (quantidade < 1)
            throw new ArgumentException("Quantidade tem que ser pelo menos 1!");
        Quantidade = quantidade;
        Preco = preco;
    }

    public override string ToString()
        => $"Produto: {Produto}, Qtde: {Quantidade}, Total: {CustoTotal}";
}

Repara que a gente definiu as propriedades explicitamente, deixou elas com init-setter (objeto imutável), botou cálculo automático do total — o código ficou mais flexível!

Chamando no programa:

var order = new Order("Bicicleta", 2, 15000);
Console.WriteLine(order); // Produto: Bicicleta, Qtde: 2, Total: 30000

3. record struct

Evolução dos structs

Antes do record struct, as structs em C# eram tipo “trabalhador raiz” — copiadas rapidinho, ficam na stack, ótimas pra dados pequenos (tipo coordenadas ou cores). Mas não tinham as vantagens dos records: nada de sintaxe posicional, with-expressions, comparação por valor automática e outras “delícias”.

Agora em C# dá pra declarar structs no estilo record:

public record struct Point(int X, int Y);
Sintaxe posicional do record struct

Mas o que isso traz de bom?

  • Implementação automática de Equals, GetHashCode, ToString — tua struct já sabe se comparar e imprimir bonito!
  • Sintaxe de clonagem with: var p2 = p1 with { X = 10 };
  • Pode usar sintaxe posicional ou corpo explícito.

Comparando: struct clássico VS record struct

struct record struct
Sintaxe posicional Não Sim
with-expression Não Sim
Imutabilidade Não (padrão) Sim (init)
Comparação por valor Não (padrão) Sim
ToString Padrão Bonitão

Sintaxe explícita de corpo para record struct

É igualzinho ao record normal, só que struct:


public record struct Rectangle
{
    public int Largura { get; init; }
    public int Altura { get; init; }

    public int Area => Largura * Altura;

    public Rectangle(int largura, int altura)
    {
        Largura = largura > 0 ? largura : throw new ArgumentException("Largura > 0");
        Altura = altura > 0 ? altura : throw new ArgumentException("Altura > 0");
    }

    public void Print()
    {
        Console.WriteLine($"Tamanho: {Largura} x {Altura}, área: {Area}");
    }
}

Exemplo de uso:

var rect = new Rectangle(10, 7);
rect.Print(); // Tamanho: 10 x 7, área: 70

// Clona e muda a largura, sem mexer no original
var wideRect = rect with { Largura = 20 };
wideRect.Print(); // Tamanho: 20 x 7, área: 140

Peculiaridades do record struct

  • Ainda é struct — value type. Copia quando atribui!
  • Todos os bônus dos records: comparação por valor, clonagem com with, ToString bonitão.
  • Recomendado pra conjuntos pequenos, compactos e imutáveis de dados, quando tu quer evitar alocação no heap.
  • Pode declarar parâmetros posicionais ou abrir o corpo explicitamente.

4. Erros comuns e pegadinhas

Mutabilidade demais: record struct não deixa os campos imutáveis automaticamente se tu declara eles normais (tipo public int Valor;). Usa init-setters pra ter struct realmente imutável!

Comparação: Se tu adiciona campos novos manualmente (sem botar na sintaxe posicional), só os campos do construtor ou com init-setter entram na comparação automática por valor.

Cópia: É struct, então... tudo copia! Não confunde com records por referência.

Confusão com with-expressions: Sempre fazem shallow copy, ou seja, NÃO copiam profundamente objetos aninhados.

2
Tarefa
C# SELF, nível 19, lição 3
Bloqueado
Criação de um record com corpo explícito
Criação de um record com corpo explícito
2
Tarefa
C# SELF, nível 19, lição 3
Bloqueado
Trabalhando com record struct
Trabalhando com record struct
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION