0Pricing
C# Academy · Aula

Sobrecarga de operadores de comparação

Implemente operadores ==, != e de ordenação.

Sobrecarga de operadores de comparação é 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.

Operadores de comparação e igualdade

Quando você sobrecarrega ==, também deve sobrecarregar != e deve substituir Equals e GetHashCode para manter consistentes todas as formas de igualdade. O C# impõe o pareamento dos operadores no momento da compilação.

Sobrecarregando == e !=

O compilador exige que == e != sejam definidos juntos. Cada um retorna um bool que indica se os operandos são considerados iguais.

using System;

public struct Point
{
    public int X, Y;
    public Point(int x, int y) { X = x; Y = y; }

    public static bool operator ==(Point a, Point b) => a.X == b.X && a.Y == b.Y;
    public static bool operator !=(Point a, Point b) => !(a == b);

    public override bool Equals(object obj) => obj is Point p && this == p;
    public override int GetHashCode() => HashCode.Combine(X, Y);
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Point(1, 2) == new Point(1, 2));
        Console.WriteLine(new Point(1, 2) != new Point(3, 4));
    }
}

Sempre substitua Equals também

Os operadores são resolvidos no momento da compilação pelo tipo estático, mas Equals é virtual e usado pelas coleções. Substitua Equals para que dicionários e List.Contains concordem com o seu ==.

using System;

public struct Point
{
    public int X, Y;
    public Point(int x, int y) { X = x; Y = y; }
    public static bool operator ==(Point a, Point b) => a.X == b.X && a.Y == b.Y;
    public static bool operator !=(Point a, Point b) => !(a == b);
    public override bool Equals(object obj) => obj is Point p && this == p;
    public override int GetHashCode() => HashCode.Combine(X, Y);
}

public class Program
{
    public static void Main()
    {
        object a = new Point(1, 2);
        object b = new Point(1, 2);
        Console.WriteLine(a.Equals(b));
    }
}

GetHashCode deve corresponder à igualdade

Se dois valores forem iguais, eles deverão retornar o mesmo código de dispersão. Caso contrário, coleções baseadas em código de dispersão, como Dictionary e HashSet, funcionarão incorretamente.

using System;
using System.Collections.Generic;

public struct Point
{
    public int X, Y;
    public Point(int x, int y) { X = x; Y = y; }
    public static bool operator ==(Point a, Point b) => a.X == b.X && a.Y == b.Y;
    public static bool operator !=(Point a, Point b) => !(a == b);
    public override bool Equals(object obj) => obj is Point p && this == p;
    public override int GetHashCode() => HashCode.Combine(X, Y);
}

public class Program
{
    public static void Main()
    {
        var set = new HashSet<Point> { new Point(1, 2) };
        Console.WriteLine(set.Contains(new Point(1, 2)));
    }
}

Operadores de ordenação < e >

Você também pode sobrecarregar os operadores relacionais. Assim como ocorre com a igualdade, < e > devem ser definidos juntos, e o mesmo vale para <= e >=.

using System;

public struct Weight
{
    public int Grams;
    public Weight(int g) { Grams = g; }

    public static bool operator <(Weight a, Weight b) => a.Grams < b.Grams;
    public static bool operator >(Weight a, Weight b) => a.Grams > b.Grams;

    public override string ToString() => Grams + "g";
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Weight(100) < new Weight(200));
        Console.WriteLine(new Weight(300) > new Weight(200));
    }
}

Igualdade para tipos de referência

Para classes, igualdade de valores significa comparar campos, não referências. Trate null com cuidado para evitar lançar uma exceção dentro do operador.

using System;

public class Person
{
    public string Name;
    public Person(string name) { Name = name; }

    public static bool operator ==(Person a, Person b)
    {
        if (ReferenceEquals(a, b)) return true;
        if (a is null || b is null) return false;
        return a.Name == b.Name;
    }
    public static bool operator !=(Person a, Person b) => !(a == b);
    public override bool Equals(object obj) => this == (obj as Person);
    public override int GetHashCode() => Name?.GetHashCode() ?? 0;
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Person("Ann") == new Person("Ann"));
    }
}

Consistência entre as formas

Todas as formas de igualdade devem concordar: ==, Equals e o código de dispersão. Implemente == com base em Equals (ou vice-versa) para que exista uma única fonte de verdade.

using System;

public struct Id
{
    public int Value;
    public Id(int value) { Value = value; }
    public bool Equals(Id other) => Value == other.Value;
    public override bool Equals(object obj) => obj is Id other && Equals(other);
    public override int GetHashCode() => Value;
    public static bool operator ==(Id a, Id b) => a.Equals(b);
    public static bool operator !=(Id a, Id b) => !a.Equals(b);
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Id(7) == new Id(7));
        Console.WriteLine(new Id(7).Equals(new Id(8)));
    }
}

Operadores versus Equals em coleções

A pesquisa em listas usa Equals, não ==, porque funciona com referências a object. Se você sobrecarregar apenas == e esquecer Equals, as pesquisas usarão a identidade da referência e poderão falhar.

using System;
using System.Collections.Generic;

public struct Tag
{
    public string Name;
    public Tag(string name) { Name = name; }
    public override bool Equals(object obj) => obj is Tag t && t.Name == Name;
    public override int GetHashCode() => Name?.GetHashCode() ?? 0;
    public static bool operator ==(Tag a, Tag b) => a.Equals(b);
    public static bool operator !=(Tag a, Tag b) => !a.Equals(b);
}

public class Program
{
    public static void Main()
    {
        var list = new List<Tag> { new Tag("red"), new Tag("blue") };
        Console.WriteLine(list.Contains(new Tag("blue")));
    }
}

Suprimindo avisos do compilador corretamente

Substituir Equals e GetHashCode juntamente com os operadores não é apenas uma questão de boa prática; o compilador avisa se você sobrecarregar == sem substituir Equals. Fazer ambos remove o aviso e evita erros.

using System;

public struct Cell
{
    public int Row, Col;
    public Cell(int r, int c) { Row = r; Col = c; }
    public override bool Equals(object obj) => obj is Cell c && c.Row == Row && c.Col == Col;
    public override int GetHashCode() => HashCode.Combine(Row, Col);
    public static bool operator ==(Cell a, Cell b) => a.Equals(b);
    public static bool operator !=(Cell a, Cell b) => !a.Equals(b);
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Cell(0, 0) == new Cell(0, 0));
    }
}

Juntando tudo

Um tipo com igualdade bem implementada define == e !=, substitui Equals e GetHashCode e encaminha todos eles para uma única comparação. Esse é o padrão ideal para tipos semelhantes a valores.

using System;
using System.Collections.Generic;

public struct Color
{
    public int R, G, B;
    public Color(int r, int g, int b) { R = r; G = g; B = b; }
    public override bool Equals(object obj) => obj is Color c && c.R == R && c.G == G && c.B == B;
    public override int GetHashCode() => HashCode.Combine(R, G, B);
    public static bool operator ==(Color a, Color b) => a.Equals(b);
    public static bool operator !=(Color a, Color b) => !a.Equals(b);
}

public class Program
{
    public static void Main()
    {
        var dict = new Dictionary<Color, string> { [new Color(255, 0, 0)] = "red" };
        Console.WriteLine(dict[new Color(255, 0, 0)]);
    }
}

Experimente por si mesmo

Implemente uma estrutura com igualdade totalmente consistente e verifique se ela funciona simultaneamente como chave de um dicionário e com o operador ==.

using System;
using System.Collections.Generic;

public struct GridPos
{
    public int Row, Col;
    public GridPos(int r, int c) { Row = r; Col = c; }
    public override bool Equals(object obj) => obj is GridPos p && p.Row == Row && p.Col == Col;
    public override int GetHashCode() => HashCode.Combine(Row, Col);
    public static bool operator ==(GridPos a, GridPos b) => a.Equals(b);
    public static bool operator !=(GridPos a, GridPos b) => !a.Equals(b);
}

public class Program
{
    public static void Main()
    {
        var grid = new Dictionary<GridPos, string> { [new GridPos(1, 1)] = "player" };
        Console.WriteLine(new GridPos(1, 1) == new GridPos(1, 1));
        Console.WriteLine(grid[new GridPos(1, 1)]);
    }
}

Verificação rápida

Relembre as regras para sobrecarregar a igualdade.

Recapitulação

Sobrecarregar operadores de comparação exige consistência.

  • == e != devem ser definidos juntos; o mesmo vale para </>.
  • Substitua Equals e GetHashCode para que correspondam a ==.
  • Valores iguais devem compartilhar o mesmo código de dispersão.
  • Encaminhe toda a igualdade para um único método de comparação para evitar divergências.

Perguntas Frequentes

A aula “Sobrecarga de operadores de comparação” é grátis?

Sim — o texto completo de “Sobrecarga de operadores de comparação” é 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 “Sobrecarga de operadores de comparação”?

Implemente operadores ==, != e de ordenação. 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 “Sobrecarga de operadores de comparação”?

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. Sobrecarga de operadores aritméticos
  2. Sobrecarga de operadores de comparação
  3. Conversões definidas pelo usuário
  4. Boas práticas para sobrecarga de operadores
← Voltar para C# Academy