C# Language
Is gelijk aan en GetHashCode
Zoeken…
Opmerkingen
Elke implementatie van Equals moet voldoen aan de volgende vereisten:
Reflexief : een object moet zichzelf evenaren.
x.Equals(x)geefttrueterug.Symmetrisch : er is geen verschil als ik x met y vergelijk of y met x - het resultaat is hetzelfde.
x.Equals(y)retourneert dezelfde waarde alsy.Equals(x).Overgankelijk : Als een object gelijk is aan een ander object en dit object gelijk is aan een derde, moet het eerste gelijk zijn aan het derde.
als(x.Equals(y) && y.Equals(z))trueretourneert, dan geeftx.Equals(z)true.Consistent : als u een object meerdere keren met een ander vergelijkt, is het resultaat altijd hetzelfde.
Opeenvolgende aanroepen vanx.Equals(y)retourneren dezelfde waarde zolang de objecten waarnaar wordt verwezen door x en y niet worden gewijzigd.Vergelijking met null : Geen object is gelijk aan
null.
x.Equals(null)retourneertfalse.
Implementaties van GetHashCode :
Geschikt voor
Equals: Als twee objecten gelijk zijn (hetgeen betekent datEqualsrendement waar), danGetHashCodemoet dezelfde waarde terug voor elk van hen.Groot bereik : als twee objecten niet gelijk zijn (
Equalszegt false), moet de kans groot zijn dat hun hash-codes verschillend zijn. Perfecte hashing is vaak niet mogelijk omdat er een beperkt aantal waarden is om uit te kiezen.Goedkoop : het moet goedkoop zijn om de hash-code in alle gevallen te berekenen.
Zie: Richtlijnen voor overbelasting is gelijk aan () en operator ==
Standaard is gelijk aan gedrag.
Equals wordt verklaard in de klasse Object zelf.
public virtual bool Equals(Object obj);
Standaard heeft Equals het volgende gedrag:
Als de instantie een referentietype is, retourneert
Equalsalleen true als de referenties hetzelfde zijn.Als de instantie een waardetype is, retourneert
Equalsalleen true als het type en de waarde hetzelfde zijn.stringis een speciaal geval. Het gedraagt zich als een waardetype.
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
//areFooClassEqual: False
Foo fooClass1 = new Foo("42");
Foo fooClass2 = new Foo("42");
bool areFooClassEqual = fooClass1.Equals(fooClass2);
Console.WriteLine("fooClass1 and fooClass2 are equal: {0}", areFooClassEqual);
//False
//areFooIntEqual: True
int fooInt1 = 42;
int fooInt2 = 42;
bool areFooIntEqual = fooInt1.Equals(fooInt2);
Console.WriteLine("fooInt1 and fooInt2 are equal: {0}", areFooIntEqual);
//areFooStringEqual: True
string fooString1 = "42";
string fooString2 = "42";
bool areFooStringEqual = fooString1.Equals(fooString2);
Console.WriteLine("fooString1 and fooString2 are equal: {0}", areFooStringEqual);
}
}
public class Foo
{
public string Bar { get; }
public Foo(string bar)
{
Bar = bar;
}
}
}
Het schrijven van een goede GetHashCode-override
GetHashCode heeft grote prestatie-effecten op Dictionary <> en HashTable.
Goede GetHashCode methoden
- moet een gelijkmatige verdeling hebben
- elk geheel getal moet ongeveer dezelfde kans hebben om terug te keren voor een willekeurige instantie
- als uw methode hetzelfde gehele getal (bijvoorbeeld de constante '999') voor elke instantie retourneert, hebt u slechte prestaties
- zou snel moeten zijn
- Dit zijn GEEN cryptografische hashes, waarbij traagheid een functie is
- hoe langzamer je hash-functie, hoe langzamer je woordenboek
- moet dezelfde HashCode retourneren op twee instanties die
Equalsaan true- als ze dat niet doen (bijvoorbeeld omdat
GetHashCodeeen willekeurig getal retourneert), zijn items mogelijk niet gevonden in eenList,Dictionaryof vergelijkbaar.
- als ze dat niet doen (bijvoorbeeld omdat
Een goede methode om GetHashCode te implementeren is om één priemgetal als startwaarde te gebruiken en daar de hashcodes van de velden van het type vermenigvuldigd met andere priemgetallen aan toe te voegen:
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 3049; // Start value (prime number).
// Suitable nullity checks etc, of course :)
hash = hash * 5039 + field1.GetHashCode();
hash = hash * 883 + field2.GetHashCode();
hash = hash * 9719 + field3.GetHashCode();
return hash;
}
}
Alleen de velden die worden gebruikt in de methode Equals moeten worden gebruikt voor de hash-functie.
Als u hetzelfde type op verschillende manieren voor Dictionary / HashTables wilt behandelen, kunt u IEqualityComparer gebruiken.
Negeren is gelijk aan en GetHashCode op aangepaste typen
Voor een klas Person zoals:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Clothes { get; set; }
}
var person1 = new Person { Name = "Jon", Age = 20, Clothes = "some clothes" };
var person2 = new Person { Name = "Jon", Age = 20, Clothes = "some other clothes" };
bool result = person1.Equals(person2); //false because it's reference Equals
Maar het definiëren van Equals en GetHashCode als volgt:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Clothes { get; set; }
public override bool Equals(object obj)
{
var person = obj as Person;
if(person == null) return false;
return Name == person.Name && Age == person.Age; //the clothes are not important when comparing two persons
}
public override int GetHashCode()
{
return Name.GetHashCode()*Age;
}
}
var person1 = new Person { Name = "Jon", Age = 20, Clothes = "some clothes" };
var person2 = new Person { Name = "Jon", Age = 20, Clothes = "some other clothes" };
bool result = person1.Equals(person2); // result is true
Als u LINQ ook gebruikt om verschillende vragen over personen te maken, worden zowel Equals als GetHashCode :
var persons = new List<Person>
{
new Person{ Name = "Jon", Age = 20, Clothes = "some clothes"},
new Person{ Name = "Dave", Age = 20, Clothes = "some other clothes"},
new Person{ Name = "Jon", Age = 20, Clothes = ""}
};
var distinctPersons = persons.Distinct().ToList();//distinctPersons has Count = 2
Is gelijk aan en GetHashCode in IEqualityComparator
Voor gegeven type Person :
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Clothes { get; set; }
}
List<Person> persons = new List<Person>
{
new Person{ Name = "Jon", Age = 20, Clothes = "some clothes"},
new Person{ Name = "Dave", Age = 20, Clothes = "some other clothes"},
new Person{ Name = "Jon", Age = 20, Clothes = ""}
};
var distinctPersons = persons.Distinct().ToList();// distinctPersons has Count = 3
Maar het definiëren van Equals en GetHashCode in een IEqualityComparator :
public class PersonComparator : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
return x.Name == y.Name && x.Age == y.Age; //the clothes are not important when comparing two persons;
}
public int GetHashCode(Person obj) { return obj.Name.GetHashCode() * obj.Age; }
}
var distinctPersons = persons.Distinct(new PersonComparator()).ToList();// distinctPersons has Count = 2
Merk op dat voor deze zoekopdracht twee objecten als gelijk worden beschouwd als zowel de waarde Equals true is geretourneerd als de GetHashCode dezelfde hash-code heeft geretourneerd voor de twee personen.