Desafio C#

Record struct e igualdade por valor

Enunciado

Crie um record struct Coordenada com as propriedades X e Y (int). No Main, crie duas coordenadas iguais e uma diferente. Use with para criar uma cópia alterando X. Exiba a igualdade entre as coordenadas e também entre a cópia e a original. Além disso, mostre que record struct é um tipo de valor usando Equals e ReferenceEquals.

Requisitos

  • Declarar record struct Coordenada com X e Y.
  • Criar instâncias, comparar com == e usar with.
  • Demonstrar que é tipo de valor com ReferenceEquals (deve retornar False).

Código inicial

using System;

// TODO: declarar o record struct Coordenada

public class Program
{
    public static void Main()
    {
        // TODO: criar coordenadas, comparar e usar with
    }
}

Saída esperada

c1 == c2: True
c1 == c3: False
copia == c1: False
ReferenceEquals(c1, c2): False
Ver dica

record struct é tipo de valor; ReferenceEquals sempre retorna False para tipos de valor, mesmo que sejam iguais.

Mostrar solução
using System;

// record struct: tipo de valor com igualdade por valor
public record struct Coordenada(int X, int Y);

public class Program
{
    public static void Main()
    {
        var c1 = new Coordenada(10, 20);
        var c2 = new Coordenada(10, 20);
        var c3 = new Coordenada(10, 30);

        // Igualdade por valor
        Console.WriteLine($"c1 == c2: {c1 == c2}"); // True
        Console.WriteLine($"c1 == c3: {c1 == c3}"); // False

        // with cria uma cópia alterando X
        var copia = c1 with { X = 15 };
        Console.WriteLine($"copia == c1: {copia == c1}"); // False

        // ReferenceEquals sempre False para tipos de valor
        Console.WriteLine($"ReferenceEquals(c1, c2): {ReferenceEquals(c1, c2)}");
    }
}

Passo a passo

  1. Declaramos Coordenada como record struct posicional, que gera propriedades X e Y e implementa igualdade por valor.
  2. Criamos c1 e c2 com os mesmos valores, e c3 com Y diferente.
  3. c1 == c2 compara os valores de X e Y e retorna True.
  4. c1 == c3 retorna False porque Y difere.
  5. c1 with { X = 15 } cria uma nova instância de Coordenada com X alterado e Y copiado.
  6. copia == c1 retorna False porque X é diferente.
  7. ReferenceEquals(c1, c2) recebe os structs em caixas separadas (boxing) e compara referências, retornando False.

Por que funciona

record struct combina a semântica de tipo de valor (armazenado na pilha, copiado por valor) com a igualdade por valor dos records. O operador with funciona tanto para record class quanto para record struct, gerando uma nova instância com as alterações. ReferenceEquals não faz sentido para tipos de valor, pois cada boxing cria um novo objeto.

Erros comuns

  • Declarar record class Coordenada em vez de record struct: ReferenceEquals poderia retornar True se fosse a mesma referência, mas o enunciado pede tipo de valor.
  • Usar == esperando igualdade por referência: em record struct, == compara valores, não referências.
  • Esquecer que with em record struct retorna uma nova instância; não modifica a original.

Outra forma de resolver

Se precisar de um tipo de valor sem igualdade por valor, use struct comum e implemente IEquatable<T> manualmente. Mas record struct é mais conciso e já traz a igualdade por valor.

Saída esperada

c1 == c2: True
c1 == c3: False
copia == c1: False
ReferenceEquals(c1, c2): False