Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of mappen te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen om mappen te wijzigen.
Tip
Dit artikel maakt deel uit van de sectie Grondbeginselen voor ontwikkelaars die al ten minste één programmeertaal kennen en C# leren. Als u nieuw bent in programmeren, begint u eerst met de Aan de slag-handleidingen.
Komt u uit een andere taal? In Java testen == bij objecten en === in JavaScript bij objecten de identiteit, niet de inhoud. C#-klassen werken standaard op dezelfde manier. In Python roept == standaard __eq__ aan en test het de inhoud, vergelijkbaar met hoe C# records vergelijkt. C# structs worden ook op waarde vergeleken wanneer u Equals aanroept.
C# onderscheidt twee soorten gelijkheid. Gelijkheid van waarden betekent dat twee exemplaren gelijk zijn wanneer hun gegevens overeenkomen. Verwijzings gelijkheid betekent dat twee variabelen alleen gelijk zijn wanneer ze verwijzen naar hetzelfde object in het geheugen. Deze voorwaarde wordt ook wel identiteit genoemd. Waardetypen vergelijken meestal gegevens en referentietypen vergelijken meestal identiteiten. Typeauteurs kunnen deze standaardinstellingen wijzigen, maar dat mentale model voorkomt subtiele bugs waarbij twee objecten die identiek lijken niet als gelijk worden beschouwd, of waarbij een mutatie via een variabele op de achtergrond verandert wat een andere variabele ziet.
Waardetypen, referentietypen en standaardgedrag voor gelijkheid
Elk type in C# is een waardetype of een verwijzingstype. Een waardetype bevat de gegevens rechtstreeks in de variabele. Een verwijzingstype bevat een verwijzing naar een object. Wanneer u een variabele van het verwijzingstype aan een andere variabele toewijst, verwijzen beide variabelen naar hetzelfde object. Zie Systeemoverzicht type voor meer informatie over waardetypen en referentietypen.
Het standaardgedrag voor gelijkheid volgt meestal het type:
-
Ingebouwde numerieke typen en opsommingen zijn waardetypen. Twee
intvariabelen zijn gelijk wanneer hun numerieke waarden overeenkomen. -
Structs zijn waardetypen. Een gewone
structgebruikt gelijkheid van waarden wanneer u Equals aanroept. - Tuples zijn waardetypen. Twee tuples zijn gelijk wanneer alle elementwaarden overeenkomen.
-
Klassen zijn referentietypen. Een gewone klasse maakt gebruik van verwijzings gelijkheid, dus
==en Equals test of twee variabelen naar hetzelfde object verwijzen.
Een klasse maakt gebruik van verwijzings gelijkheid. Twee afzonderlijke objecten met dezelfde gegevens zijn niet gelijk, maar twee variabelen die naar hetzelfde object verwijzen, zijn gelijk:
var order1 = new Order(42, "Shoes");
var order2 = new Order(42, "Shoes");
Console.WriteLine(order1 == order2); // => False
Console.WriteLine(order1.Equals(order2)); // => False
Console.WriteLine(ReferenceEquals(order1, order2)); // => False
Order order3 = order1;
Console.WriteLine(order1 == order3); // => True
A struct toont waarde gelijkheid via Equals. Twee struct-exemplaren zijn gelijk wanneer de velden overeenkomen:
var pt1 = new Point(3, 4);
var pt2 = new Point(3, 4);
Console.WriteLine(pt1.Equals(pt2)); // => True
Gewone structs krijgen geen vooraf gedefinieerde == operator. Schrijven p1 == p2 op een gewone struct compileert alleen als de struct zijn eigen operator ==declareert. Als u operatorvergelijkingen voor een struct nodig hebt, definieert == en != als een paar en houdt u deze consistent met Equals en GetHashCode.
Tuples zijn ook waardetypen. Twee tuples zijn gelijk wanneer elke elementwaarde overeenkomt. Elementnamen in een tuple met namen zijn alleen een hulpmiddel tijdens het compileren en worden bij vergelijking niet in aanmerking genomen. Alleen posities en waarden zijn belangrijk:
var t1 = (Name: "Grace", Role: "Engineer");
var t2 = (Name: "Grace", Role: "Engineer");
Console.WriteLine(t1 == t2); // => True
Zie Tuples en deconstructie voor meer informatie over tuplesyntaxis en deconstructie.
Gebruiken Object.ReferenceEquals om identiteit rechtstreeks te testen
ReferenceEquals test altijd identiteit, ongeacht hoe een type overschrijft Equals of overbelast ==. Gebruik deze als identiteitsdiagnose wanneer u wilt controleren of twee variabelen naar hetzelfde object verwijzen:
var doc1 = new Document("Report");
var doc2 = new Document("Report");
var doc3 = doc1;
Console.WriteLine(ReferenceEquals(doc1, doc2)); // => False
Console.WriteLine(ReferenceEquals(doc1, doc3)); // => True
Een veelvoorkomende toepassing is binnen een Equals override om de volledige vergelijking over te slaan: wanneer beide argumenten naar dezelfde instantie verwijzen, zijn ze altijd gelijk zonder de afzonderlijke velden te controleren.
Note
Wanneer variabelen worden getypt als een interface, == controleert u of de interfacevariabelen naar hetzelfde object verwijzen. Een aanroep van Equals voert nog steeds de implementatie van het onderliggende object uit.
Note
ReferenceEquals retourneert false altijd bij het vergelijken van waardetypen, zelfs als beide argumenten dezelfde waarden bevatten. Dit gedrag treedt op omdat elk argument van het waardetype onafhankelijk in een afzonderlijk heap-object wordt geplaatst wanneer dit wordt doorgegeven aan ReferenceEquals.
Typen kunnen verschillende gelijkheidssemantiek definiëren
Typen kunnen gelijkheidssemantiek definiëren die verschillen van het standaardgedrag. De meest voorkomende reden is het implementeren van gelijkheid van waarden. Als u een type maakt dat gegevens vertegenwoordigt, zoals een bankrekening, een product in voorraad of een gebruiker in een systeem, kunt u instanties met dezelfde waarden overwegen als gelijk. Kies recordtypen voor het implementeren van gelijkheid van waarden en de compiler genereert alle benodigde gelijkheidsleden voor u.
Note
Tekenreeksen zijn klassen, maar == en Equals vergelijken de inhoud van tekenreeksen, niet de identiteit.
-
==: de gelijkheidsoperator. De meeste typen gebruiken deze operator als primaire gelijkheidscontrole. Het gedrag is afhankelijk van of het type een ingebouwde of door de gebruiker gedefinieerde==operator heeft. -
!=: de ongelijkheidsoperator. Wanneer een type een door de gebruiker gedefinieerde==operator definieert, moet het ook definiëren!=. - Equals: een virtuele methode die door elk type wordt overgenomen. U kunt deze overschrijven om de gelijkheidssemantiek voor een type te wijzigen.
- GetHashCode: een virtuele methode die wordt gebruikt door op hash gebaseerde verzamelingen. Wanneer twee waarden gelijk zijn, moeten hun hash-codes ook gelijk zijn.
- ReferenceEquals: een statische methode die altijd identiteit test.
Records gebruiken voor gelijkheid van waarden
Gebruik de record wijzigingsfunctie om een gelijkheid van gegevensgerichte typewaarden te geven wanneer het type een record kan zijn. De compiler genereert Equals, GetHashCodeen ==/!= leden die elke gedeclareerde eigenschapswaarde vergelijken.
A record class is nog steeds een verwijzingstype, maar vergelijkt waarden in plaats van identiteit:
var person1 = new Person("Ada", "Lovelace");
var person2 = new Person("Ada", "Lovelace");
Console.WriteLine(person1 == person2); // => True
Console.WriteLine(person1.Equals(person2)); // => True
Console.WriteLine(ReferenceEquals(person1, person2)); // => False
ReferenceEquals bevestigt dat person1 en person2 zijn verschillende objecten in het geheugen, terwijl == en Equals retourneren True omdat de door de compiler gegenereerde gelijkheid eigenschapswaarden vergelijkt.
Dezelfde compilergeneratie is van toepassing op record struct typen:
var dim1 = new Dimension(1920, 1080);
var dim2 = new Dimension(1920, 1080);
Console.WriteLine(dim1 == dim2); // => True
Console.WriteLine(dim1.Equals(dim2)); // => True
Recordtypen genereren de volledige gelijkheidsset voor hun eigen type. Zowel record class als record struct typen overschrijven Equals en GetHashCode. Ze genereren == en != operators, plus een getypte Equals methode voor het recordtype. In tegenstelling tot een gewone struct, ondersteunt een record struct daarom == en != automatisch. Zie Records voor meer informatie over recordtypen en hun gelijkheidssemantiek.
Records met leden van het referentietype
Record gelijkheid maakt gebruik van de eigen gelijkheidssemantiek van de leden. Elke eigenschap of elk veld wordt vergeleken met behulp van een eigen Equals methode. Voor de meeste scalaire waarden, zoals int, stringof DateTime, vergelijkt deze benadering de waarden van de recordleden. De subtiliteit ontstaat met algemene onveranderbare verzamelingen, zoals List<T> of T[]: deze typen worden vergeleken met verwijzing, dus twee recordexemplaren die verschillende lijstobjecten met dezelfde inhoud bevatten, worden niet als gelijk beschouwd door de gesynthetiseerde record gelijkheid.
var playlist1 = new Playlist("Chill", new List<string> { "Song A", "Song B" });
var playlist2 = new Playlist("Chill", new List<string> { "Song A", "Song B" });
Console.WriteLine(playlist1.Equals(playlist2)); // => False (different List instances)
Console.WriteLine(playlist1.Tracks.SequenceEqual(playlist2.Tracks)); // => True
playlist1 en playlist2 zijn afzonderlijke List<string> exemplaren. Hoewel de inhoud ervan overeenkomt, retourneert Equalsfalse.
Wanneer u gelijkheid van records nodig hebt om de inhoud van de verzameling weer te geven, hebt u een aantal opties:
-
Implementeer
IEquatable<T>voor de record en overschrijfEqualsom Enumerable.SequenceEqual te gebruiken voor de leden van de verzameling. -
Gebruik een verzamelingstype met gelijkheid van waarden , bijvoorbeeld een aangepast
IEqualityComparer<T>type of een type waarvan de eigenEqualselementen worden vergeleken. - Ontwerp rond identiteit: als de record een entiteit vertegenwoordigt in plaats van een pure waarde, is verwijzings gelijkheid voor de leden van de verzameling mogelijk opzettelijk.
Important
Handmatige implementatie van gelijkheid is tegenwoordig zeldzaam in C#. Records verwerken automatisch het algemene scenario van gelijkheid van waarden. Als u gelijkheid handmatig moet implementeren, bijvoorbeeld omdat uw type moet worden afgeleid van een niet-recordbasisklasse, raadpleegt u Gelijkheid zelf implementeren wanneer een type geen record kan zijn in de taalverwijzing.
Zie ook
- Typesysteemoverzicht
- Klassen
- Structuren
- Records
- Tuples en deconstructie.
- Gelijkheidsoperators (taalreferentie).
- Gelijkheid in klassenhiërarchieën - geavanceerde richtlijnen voor polymorfe gelijkheid.
- Rekenkundige, vergelijkings-, logische en toewijzingsoperatoren : de gelijkheidsoperatorenquête naast rekenkundige, logische en toewijzingsoperatoren.