C# Academy · Oppitunti

Vertailuoperaattorien ylikuormitus

Toteuttakaa operaattorit ==, != ja järjestämistä varten.

Oppitunti 2/413 vaihetta

Vertailuoperaattorien ylikuormitus on ilmainen C# Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu C# Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. C# Academy-kurssilla on yhteensä 4 oppituntia.

Vertailuoperaattorit ja yhtäsuuruus

Kun ylikuormitatte operaattorin ==, teidän on ylikuormitettava myös !=. Lisäksi Equals- ja GetHashCode-metodit kannattaa korvata, jotta kaikki yhtäsuuruuden muodot pysyvät yhdenmukaisina. C# valvoo operaattoriparia käännösaikana.

Operaattorien == ja != ylikuormitus

Kääntäjä edellyttää, että == ja != määritellään yhdessä. Kumpikin palauttaa bool-arvon, joka ilmaisee, pidetäänkö operandeja yhtä suurina.

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));
    }
}

Korvatkaa aina myös Equals

Operaattorit ratkaistaan käännösaikana staattisen tyypin perusteella, mutta Equals on virtuaalinen ja kokoelmat käyttävät sitä. Korvatkaa Equals, jotta sanakirjat ja List.Contains ovat samaa mieltä operaattorin == kanssa.

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));
    }
}

GetHashCoden on vastattava yhtäsuuruutta

Jos kaksi arvoa ovat yhtä suuria, niiden on palautettava sama hajautuskoodi. Muussa tapauksessa hajautukseen perustuvat kokoelmat, kuten Dictionary ja HashSet, toimivat virheellisesti.

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)));
    }
}

Järjestysoperaattorit < ja >

Myös relaatio-operaattoreita voi ylikuormittaa. Kuten yhtäsuuruusoperaattorien tapauksessa, < ja > on määriteltävä yhdessä, samoin <= ja >=.

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));
    }
}

Viitetyyppien yhtäsuuruus

Luokissa arvojen yhtäsuuruus tarkoittaa kenttien, ei viitteiden, vertaamista. Käsitelkää null huolellisesti, jotta operaattori ei heitä poikkeusta.

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"));
    }
}

Yhdenmukaisuus eri muodoissa

Kaikkien yhtäsuuruuden tarkistustapojen on annettava sama tulos: ==, Equals ja hajautuskoodi. Toteuttakaa == Equals-metodin avulla (tai päinvastoin), jotta totuudelle on vain yksi lähde.

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)));
    }
}

Operaattorit ja Equals kokoelmissa

Listahaku käyttää Equals-metodia, ei operaattoria ==, koska se toimii object-viitteillä. Jos ylikuormitatte vain operaattorin == ja unohdatte Equals-metodin, hauissa käytetään viite-identiteettiä ja ne voivat epäonnistua.

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")));
    }
}

Kääntäjän varoitusten asianmukainen poistaminen

Equals- ja GetHashCode-metodien korvaaminen operaattorien yhteydessä ei ole vain hyvien tapojen mukaista. Kääntäjä antaa varoituksen, jos ylikuormitatte operaattorin == korvaamatta Equals-metodia. Kun teette molemmat, varoitus poistuu ja virheet estyvät.

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));
    }
}

Kaiken yhdistäminen

Hyvin toimiva yhtäsuuruutta tukeva tyyppi määrittelee operaattorit == ja !=, korvaa metodit Equals ja GetHashCode sekä ohjaa ne kaikki yhden vertailun kautta. Tämä on arvon kaltaisten tyyppien tavoiteltu toteutustapa.

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)]);
    }
}

Kokeilkaa itse

Toteuttakaa täysin yhdenmukainen yhtäsuuruutta tukeva rakenne ja varmistakaa, että se toimii samanaikaisesti sanakirjan avaimena ja operaattorin == kanssa.

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)]);
    }
}

Pikatarkistus

Palauttakaa mieleenne yhtäsuuruuden ylikuormittamista koskevat säännöt.

Kertaus

Vertailuoperaattorien ylikuormitus edellyttää yhdenmukaisuutta.

  • == ja != on määriteltävä yhdessä, samoin </>.
  • Korvatkaa Equals ja GetHashCode niin, että ne vastaavat operaattoria ==.
  • Yhtä suurilla arvoilla on oltava sama hajautuskoodi.
  • Ohjatkaa kaikki yhtäsuuruustarkistukset yhden vertailumetodin kautta, jotta toteutukset eivät ajaudu erilleen.
Aloita maksutta

Opi C# tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
93
Oppitunnit
346

Usein kysytyt kysymykset

Onko oppitunti ”Vertailuoperaattorien ylikuormitus” ilmainen?

Kyllä – oppitunnin ”Vertailuoperaattorien ylikuormitus” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko C# Academy-kurssin, päivitä CoddyKit PROhon. C# Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Vertailuoperaattorien ylikuormitus”?

Toteuttakaa operaattorit ==, != ja järjestämistä varten. Harjoittelet C# Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni C# Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin C# Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”Vertailuoperaattorien ylikuormitus”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä C# Academy-oppitunnilla?

Kyllä. Jokainen C# Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Aritmeettisten operaattorien ylikuormitus
  2. Vertailuoperaattorien ylikuormitus
  3. Käyttäjän määrittämät muunnokset
  4. Operaattorien ylikuormituksen parhaat käytännöt
← Takaisin: C# Academy