0Pricing
C# Academy · Aula

Imutabilidade com init e with

Use propriedades de atribuição exclusiva com init para criar objetos imutáveis e expressões with para produzir cópias modificadas sem alterar o original.

Imutabilidade com init e with é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.

O que é imutabilidade?

Um objeto imutável não pode ser alterado depois de criado. A imutabilidade evita alterações acidentais, torna os objetos seguros para uso em várias linhas de execução por padrão e simplifica o raciocínio sobre o código. O C# oferece acessores init e expressões with para tornar a imutabilidade prática.

Acessores somente com init

Um acessador init permite definir uma propriedade durante a inicialização do objeto (no construtor ou no inicializador de objeto), mas nunca depois. Ele é a contraparte imutável de set.

public class Point
{
    public double X { get; init; }
    public double Y { get; init; }
}

var p = new Point { X = 3.0, Y = 4.0 }; // OK — init phase
p.X = 5.0; // COMPILE ERROR — cannot set after init

// All of these are valid init-phase assignments:
var p2 = new Point(X: 1.0, Y: 2.0);
var p3 = new Point { X = 0, Y = 0 };

init nas propriedades posicionais de registros

As propriedades posicionais de registros aceitam apenas init por padrão — é isso que torna os registros imutáveis. O compilador gera get; init; para cada parâmetro posicional.

// This record:
public record Person(string Name, int Age);

// Is equivalent to:
public record Person
{
    public string Name { get; init; }
    public int Age    { get; init; }
    public Person(string Name, int Age) { this.Name = Name; this.Age = Age; }
    // + Deconstruct, Equals, GetHashCode, ToString
}

var alice = new Person("Alice", 30);
alice.Name = "Bob"; // COMPILE ERROR

Expressões with: mutação não destrutiva

Uma expressão with cria uma cópia de um registro com propriedades específicas alteradas. O original permanece inalterado — isso é imutabilidade verdadeira.

public record Person(string Name, int Age, string Email);

var alice = new Person("Alice", 30, "alice@example.com");

// Create a modified copy — alice is unchanged
var olderAlice = alice with { Age = 31 };
var renamed    = alice with { Name = "Alicia", Email = "alicia@example.com" };

Console.WriteLine(alice.Name);      // Alice (unchanged)
Console.WriteLine(olderAlice.Age);  // 31
Console.WriteLine(renamed.Name);    // Alicia

with em tipos que não são registros

O C# 10 permite usar with em qualquer estrutura ou classe que tenha semântica de construtor de cópia — mas seu uso é mais natural com registros. Para classes, você precisa implementá-lo manualmente.

// struct with with-expression:
public struct Temperature
{
    public double Celsius { get; init; }
    public double Fahrenheit => Celsius * 9 / 5 + 32;
}

var t1 = new Temperature { Celsius = 20 };
var t2 = t1 with { Celsius = 25 }; // copy with change
Console.WriteLine(t1.Celsius); // 20 — unchanged
Console.WriteLine(t2.Celsius); // 25

Encadeando expressões with

Encadeie várias expressões with para criar transformações complexas, fazendo com que cada etapa crie um novo valor imutável a partir do anterior.

public record Order(int Id, string Status, decimal Total, DateTime UpdatedAt);

var order = new Order(42, "Pending", 99.99m, DateTime.UtcNow);

// Apply a promotion discount then mark as confirmed
var finalOrder = order
    with { Total    = order.Total * 0.9m }    // 10% off
    with { Status   = "Confirmed" }
    with { UpdatedAt = DateTime.UtcNow };

Console.WriteLine(order.Status);     // Pending (original unchanged)
Console.WriteLine(finalOrder.Status); // Confirmed

Propriedades calculadas em tipos imutáveis

As propriedades derivadas em tipos imutáveis são naturalmente puras — elas calculam seu valor a partir das propriedades fixas e sempre retornam o mesmo resultado para a mesma entrada.

public record Money(decimal Amount, string Currency)
{
    public Money Add(Money other)
    {
        if (Currency != other.Currency)
            throw new InvalidOperationException("Currency mismatch");
        return this with { Amount = Amount + other.Amount };
    }

    public Money Multiply(decimal factor) =>
        this with { Amount = Amount * factor };

    public override string ToString() =>
        $"{Amount:F2} {Currency}";
}

var price = new Money(10.00m, "USD");
var tax   = price.Multiply(0.08m);
var total = price.Add(tax);
Console.WriteLine(total); // 10.80 USD

Coleções imutáveis

Combine registros com ImmutableList<T> e outros tipos de System.Collections.Immutable para criar estruturas de dados totalmente imutáveis.

using System.Collections.Immutable;

public record ShoppingCart(
    string UserId,
    ImmutableList<CartItem> Items)
{
    public ShoppingCart AddItem(CartItem item) =>
        this with { Items = Items.Add(item) };

    public ShoppingCart RemoveItem(int productId) =>
        this with { Items = Items.RemoveAll(i => i.ProductId == productId) };

    public decimal Total => Items.Sum(i => i.Price * i.Quantity);
}

Segurança entre linhas de execução por meio da imutabilidade

Objetos imutáveis são inerentemente seguros para uso em várias linhas de execução — não é necessária sincronização ao compartilhá-los entre linhas de execução, pois seu estado não pode mudar após a construção.

// Immutable config record shared across all threads safely
public record AppConfig(
    string ConnectionString,
    int MaxRetries,
    TimeSpan Timeout);

// Register as singleton — safe because record is immutable
builder.Services.AddSingleton(
    new AppConfig(
        ConnectionString: config["DB"]!,
        MaxRetries: 3,
        Timeout: TimeSpan.FromSeconds(30)));

// Any thread can read this simultaneously without locks

No mundo real: origem funcional de eventos

Registros imutáveis combinam naturalmente com a origem de eventos: cada evento de domínio é imutável, e o estado é derivado pela combinação dos eventos — sem mutação, sem surpresas.

public record OrderState(
    int Id,
    string Status = "Draft",
    decimal Total = 0m);

public static OrderState Apply(OrderState state, object evt) => evt switch
{
    OrderPlaced   e => state with { Status = "Pending", Total = e.Total },
    OrderShipped  _ => state with { Status = "Shipped" },
    OrderCancelled _ => state with { Status = "Cancelled" },
    _ => state
};

// Fold events to get current state:
var state = events.Aggregate(
    new OrderState(id),
    Apply);

Verificação rápida

O que uma expressão 'with' faz com o registro original?

Recapitulação: imutabilidade com init e with

Principais conclusões:

  • Acessador init: pode ser definido somente durante a inicialização, nunca depois
  • As propriedades posicionais de registros aceitam apenas init por padrão
  • Expressão with: cria uma cópia modificada — o original permanece inalterado
  • Encadeie expressões with para transformações em várias etapas
  • Tipos imutáveis são seguros para uso em várias linhas de execução sem sincronização
  • Combine-os com ImmutableList<T> para criar grafos de objetos totalmente imutáveis

Perguntas Frequentes

A aula “Imutabilidade com init e with” é grátis?

Sim — o texto completo de “Imutabilidade com init e with” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.

O que vou aprender em “Imutabilidade com init e with”?

Use propriedades de atribuição exclusiva com init para criar objetos imutáveis e expressões with para produzir cópias modificadas sem alterar o original. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar C# Academy?

Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Imutabilidade com init e with”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de C# Academy?

Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Tipos record: fundamentos e sintaxe
  2. Imutabilidade com init e with
  3. Igualdade de valores e desconstrução
  4. Records no design orientado a domínios
← Voltar para C# Academy