A feladat az egyenlőség számos tulajdonságát szemlélteti a C#-ban:
Object.Equals()== és a != operátorral vizsgáljuk egyenlőség szempontjából. Ez idiomatikusabbnak számít, mint az Equals() metódus használata, amely ezeknél a típusoknál szintén elérhető. A Java-programozók legyenek éberek: amikor stringekkel dolgoznak, tudniuk kell, hogy a == a C#-ban érték szerint hasonlít össze, Javában viszont referenciák szerint, amikor visszatérnek korábbi nyelvükhöz.object-től örökölt Equals() metódussal hasonlítjuk össze. Ha az egyenlőségvizsgálat célja annak biztosítása, hogy két objektum pontosan ugyanaz a példány, akkor az object implementációjára hagyatkozva is elegendő. Ha nem, felül kell írnod az object.Equals() metódust.Equals() metódust felül kell írni.Equals() az egyszerű típusú tagokon ==-s egyenlőségvizsgálatokat, a referenciatípusokon pedig rekurzív Equals()-hívásokat fog tartalmazni.class StatusBar
{
private readonly int width = 200, height = 20;
public override bool Equals(object other)
{
// ... null and type checks and performance optimisations
return width == (other as StatusBar).width && height == (other as StatusBar).height;
}
}
class Window
{
private readonly string title = "Main";
private readonly StatusBar statusBar = new StatusBar();
public override bool Equals(object other)
{
// ... null and type checks and performance optimisations
return title == (other as Window).title && statusBar.Equals((other as Window).statusBar);
}
}
object.ReferenceEquals() metódussal hasonlítható össze két objektum annak megállapítására, hogy ugyanaz-e a példány. Ez áttekinthetőbbé teszi a kódot, és elengedhetetlen ott, ahol az Equals() és a == már felül van írva vagy túl van terhelve.var winA = new Window(); // above code shows that all windows are equal
var winB = new Window();
ReferenceEquals(winA, winB);
// => false
var winC = winA;
ReferenceEquals(winA, winC);
// => true
public override bool Equals(object obj) mellett az IDE-k általában legenerálják a protected bool Equals(FacialFeatures other) túlterhelést is, amely öröklődés esetén használható. A leszármazott osztály meghívhatja az ősosztály Equals() metódusát, majd hozzáadhatja a saját vizsgálatát.== operátort, hacsak nem túlterhelted az == operátort és az Equals() metódust is az osztályodban (lásd az operator-overloading feladatot), vagy hacsak nem csak az számít, hogy a referenciák egyenlők.struct-ok egyenlőségvizsgálatával a structs feladat foglalkozik.tuple-ök egyenlőségével a tuples feladat foglalkozik.protected bool Equals(T other)
{
return field1 == other.field1 && field2.Equals(other.field2);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((T) obj);
}
SequenceEquals() metódust, LINQ nélkül viszont mindkét gyűjteményen végig kell iterálni, és az elemeket egyenként összehasonlítani.== és != operátort a saját osztályaiddal, a operator-overloading feladatban olvashatsz.Object.GetHashCode()object.GetHashCode() egy 32 bites egész szám formájában ad vissza egy hash-kódot. A hash-kódot a szótár- és halmazosztályok, például a Dictionary<T> és a HashSet<T> használják arra, hogy hatékonyan tároljanak és kérdezzenek le objektumokat. Szótárak esetében a hash-elés a kulcsokhoz kapcsolódik.Equals() metódust, akkor a GetHashCode() metódust is felülírd. Az Equals() és a GetHashCode() között van egy kapcsolat, amelynek teljesülnie kell ahhoz, hogy a szótár- és halmazosztályok, valamint minden más hash-kódot használó osztály helyesen működjön. Elvárás, hogy úgy implementáld a metódust, hogy ne állíts csapdát azoknak a karbantartóknak, akik később esetleg egy hash-kód alapú gyűjteményt adnak hozzá.Equal() igazat ad vissza), akkor a két objektum GetHashCode() metódusának ugyanazt az értéket kell visszaadnia. Ez fordítva nem igaz. A kapcsolat nem szimmetrikus. Képzelj el egy keresőfüggvényt, amely először a hash-kód alapján egy „bucketbe” megy, majd az egyenlőségvizsgálat segítségével kiválasztja az adott elemet.HashCode.Combine() meghívása, átadva neki az egyenlőségvizsgálatban használt értékeket (vagy azok egy részhalmazát). Tartsd észben: minél több információt adsz át a Combine() metódusnak, annál hatékonyabb lesz várhatóan a hash-implementáció.public class Assessment
{
private int rating;
private Person boss;
public override int GetHashCode()
{
return HashCode.Combine(rating, boss);
}
}
A teljesítmény kismértékű javítása érdekében, különösen amikor az objektumok gyűjteményekhez tartoznak, hozzáadhatsz egy túlterhelt tagot: public bool Equals(T other).
Ez bizonyos mennyiségű típusellenőrzést takarít meg a referenciatípusoknál, az értéktípusoknál pedig egy boxolási lépést, mivel nem kell objektummá alakítani (boxolni) őket a public override bool Equals(object other) argumentumaként.
Ha hozzáadod az IEquatable<T> interfészt az osztályodhoz, az megköveteli a túlterhelés implementálását. Hacsak a kódod nem tartalmaz olyan rutinokat, amelyek IEquatable<T> típusú objektumokat fogadnak (és feltehetően valami érdekeset tesznek az egyenlőséggel kapcsolatban, függetlenül az implementáló osztálytól), valójában nincs más nyomós ok az interfész felvételére.
IEqualityComparer<T>Ha van egy osztályod, amely két különböző módon is egyedileg azonosítható, mondjuk egy Person osztály, amely egy SSID-vel és egy egyedi e-mail-címmel azonosítható, akkor a .NET eszközt nyújt arra, hogy két különböző gyűjtemény különböző hash-kód- és egyenlőségvizsgálatot használhasson. Mindkettőnek lehet saját, eltérő IEqualityComparer<T> implementációja, saját Equals() és GetHashCode() metódussal. Lehet egy szótárad SSID-ra és egy másik e-mail-címre kulcsolva.
Amikor IEqualityComparer<T> van használatban, az elemeket reprezentáló osztályon általában továbbra is felülírod az Equals() és a GetHashCode() metódust, hogy elkerüld a gyűjteményosztályokon kívüli problémákat.
Az IEqualityComparer<T> használatakor az egyik szempont, hogy a privát metódusok és hasonlók nem lesznek elérhetők az egyenlőségvizsgálat számára.
Ha csak egy hash-elt gyűjtemény van használatban, akkor jobb lehet elkerülni az IEqualityComparer<T> használatát, és az egyenlőséget meg a hash-kódot magában az objektumban elhelyezni. Eleve nem ideális, hogy egy olyan kulcsfontosságú függőséget, mint amilyen az objektum és a hash-elt gyűjtemény között van, a fordító nem tud kikényszeríteni, de ha a hash-elési és összehasonlítási logika máshol van, akkor a karbantartónak még könnyebb lenne úgy módosítania egy osztály tagjait, hogy nem törődik a gyűjteményre gyakorolt következményekkel.
Az egyik primitív, amely próbára teheti a gyanútlan programozót, a lebegőpontos értékek egyenlőségének vizsgálata. Ezt a floating-point-numbers fogalom about.md dokumentuma tárgyalja.
Ez a cikk bemutat néhány döntést, amelyet az egyenlőséggel és az öröklődéssel kapcsolatban meg kell hozni. Ezek csak akkor érintenek, ha egy osztály és egy leszármaztatott osztály példányaival dolgozol, és a kettő közötti egyenlőséget kell vizsgálnod.