Médio C#

readonly struct imutável

Enunciado

Transforme a struct Retangulo em readonly struct com propriedades somente leitura. Adicione um método ComLargura(double novaLargura) que retorna um novo Retangulo com a largura alterada, sem modificar o original. Demonstre no Main.

Requisitos

  • Declarar public readonly struct Retangulo.
  • Usar propriedades Largura e Altura somente leitura (get).
  • Implementar ComLargura(double) retornando nova instância.
  • No Main, criar r1, chamar ComLargura(10) e imprimir ambos.

Código inicial

using System;

// Implemente a readonly struct Retangulo

class Program
{
    static void Main()
    {
        // Demonstre a imutabilidade
    }
}

Saída esperada

r1 = (3, 4)
r2 = (10, 4)
Ver dica

Em readonly struct, todos os campos devem ser readonly. O método ComLargura retorna new Retangulo(novaLargura, Altura).

Mostrar solução
using System;

// readonly struct: imutável após construção
public readonly struct Retangulo
{
    public double Largura { get; }
    public double Altura { get; }

    public Retangulo(double largura, double altura)
    {
        Largura = largura;
        Altura = altura;
    }

    // Retorna uma nova instância com a largura alterada
    public Retangulo ComLargura(double novaLargura) => new Retangulo(novaLargura, Altura);

    public override string ToString() => $"({Largura}, {Altura})";
}

class Program
{
    static void Main()
    {
        Retangulo r1 = new Retangulo(3, 4);
        Retangulo r2 = r1.ComLargura(10); // novo objeto, r1 intacto

        Console.WriteLine($"r1 = {r1}");
        Console.WriteLine($"r2 = {r2}");
    }
}

Passo a passo

  1. Declaramos public readonly struct Retangulo. O modificador readonly garante que todos os campos sejam somente leitura.
  2. Usamos propriedades autoimplementadas { get; } para expor os valores sem permitir alteração externa.
  3. O construtor inicializa as propriedades. Como são readonly, só podem ser atribuídas no construtor.
  4. ComLargura cria e retorna um novo Retangulo com a largura desejada, mantendo a altura.
  5. No Main, chamamos r1.ComLargura(10) e guardamos em r2. r1 permanece inalterado.
  6. Imprimimos ambos para confirmar a imutabilidade.

Por que funciona

readonly struct impede modificações após a construção, eliminando bugs de mutação acidental. Métodos que "alteram" retornam novas instâncias, seguindo o padrão funcional. Isso também permite ao compilador evitar cópias defensivas ao passar a struct como argumento in, melhorando desempenho.

Erros comuns

  • Tentar atribuir Largura fora do construtor: r1.Largura = 5; gera erro CS0200 (propriedade somente leitura).
  • Esquecer readonly nos campos: se usar campos públicos, o compilador exige readonly em cada um; com propriedades { get; } isso é automático.
  • Retornar this em vez de nova instância: public Retangulo ComLargura(double l) { Largura = l; return this; } não compila em readonly struct.

Outra forma de resolver

Usar um método de extensão ou um with expression (C# 10+):

Retangulo r2 = r1 with { Largura = 10 };

Para isso, a struct precisa ser record struct ou ter propriedades init. É mais conciso, mas exige C# 10+.

Saída esperada

r1 = (3, 4)
r2 = (10, 4)