How do I navigate through references that are null in Groovy?

C# Ligestilling: == vs. Equals() Forklaret

19/01/2018

Rating: 4.22 (16173 votes)

At sammenligne to værdier for lighed virker som et af de mest grundlæggende koncepter inden for programmering. Men i et sprog som C# er virkeligheden mere nuanceret. Måden, hvorpå lighed evalueres, kan variere drastisk afhængigt af datatyperne og de metoder, du bruger. En almindelig kilde til forvirring og fejl er forskellen mellem at bruge lighedsoperatoren == og .Equals() metoden. Dette bliver især tydeligt, når man håndterer strenge, der kan være null. Hvis man for eksempel forsøger at kalde s1.Equals(s2), hvor s1 er null, vil programmet kaste en NullReferenceException. Bruger man derimod den statiske metode string.Equals(s1, s2), håndteres null-værdier elegant, og metoden returnerer blot false. Denne artikel dykker ned i disse forskelle og giver en omfattende guide til, hvordan man korrekt sammenligner objekter i C#.

Which operator returns true if a value is equal to a string?
For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. For reference types other than string, == returns true if its two operands refer to the same object. For the string type, == compares the values of the strings.
Indholdsfortegnelse

Den Almindelige `==` Operator: Mere End Bare Værdi

Den mest intuitive måde at sammenligne to værdier på er med == operatoren. Dens opførsel afhænger dog helt af, hvilke datatyper den arbejder med: værdityper eller referencetyper.

Sammenligning af Værdityper

For simple værdityper som int, double, bool eller DateTime, gør == operatoren præcis, hvad man forventer: den sammenligner de faktiske værdier. Hvis de to værdier er identiske, returnerer den true, ellers false. Dette er ligetil og forårsager sjældent problemer.

var d1 = DateTime.Now.Date; var d2 = DateTime.Now.Date; Console.WriteLine(d1 == d2); // Skriver True, da dato-værdierne er ens int a = 5; int b = 5; Console.WriteLine(a == b); // Skriver True 

Sammenligning af Referencetyper

Her bliver det kompliceret. For de fleste referencetyper (objekter, der nedarver fra System.Object), sammenligner == operatoren som standard ikke objekternes indhold. I stedet tjekker den, om de to variabler refererer til præcis det samme objekt i hukommelsen. Hvis du opretter to separate objekter, selv med identisk indhold, vil == returnere false.

var sb1 = new StringBuilder("Hej Verden"); var sb2 = new StringBuilder("Hej Verden"); Console.WriteLine(sb1 == sb2); // Skriver False, da de er to forskellige objekter var sb3 = sb1; Console.WriteLine(sb1 == sb3); // Skriver True, da de refererer til samme objekt 

Undtagelsen: `string`-typen

Streng-typen er en referencetype, men den er designet til at opføre sig som en værditype i mange sammenhænge. For at gøre udvikleres liv lettere, overskriver `string`-typen == operatoren, så den sammenligner strengenes indhold tegn for tegn i stedet for deres hukommelsesreference. Dette er grunden til, at du intuitivt kan sammenligne to strenge med == og få det forventede resultat.

string s1 = "Blue"; var sb = new StringBuilder("Bl"); sb.Append("ue"); string s2 = sb.ToString(); Console.WriteLine(s1 == s2); // Skriver True, fordi indholdet er det samme Console.WriteLine(object.ReferenceEquals(s1, s2)); // Skriver False, de er forskellige objekter 

Andre typer i .NET-frameworket, som Uri og Version, har også en overskrevet == operator, der sammenligner værdi i stedet for reference.

`.Equals()` Metoden: Den Virtuelle og Fleksible Løsning

Når == operatorens compile-time-opførsel ikke er tilstrækkelig, især i scenarier med nedarvning, kommer .Equals() metoden til undsætning. Det er en virtuel metode defineret i System.Object, hvilket betyder, at hver klasse kan levere sin egen specifikke implementering af lighed.

Fordi .Equals() er virtuel, bliver den korrekte version af metoden kaldt ved runtime baseret på objektets faktiske type, ikke den type variablen er erklæret som. Dette løser problemet, vi så med ==, når et objekt castes til object.

What is null safe operator stack overflow Groovy?
Stack Overflow groovy null safe operator, identifying what was null? The null safe operator in Groovy is great for reducing code and making things more readable. We can go from this:
string s1 = "Test"; string s2 = "Test"; object o1 = s1; // == fejler på grund af compile-time type (object) Console.WriteLine(o1 == s2); // False // .Equals() virker på grund af runtime type (string) Console.WriteLine(o1.Equals(s2)); // True 

Konsistensens Treenighed: `==`, `Equals` og `GetHashCode`

Når du designer dine egne klasser eller structs og har brug for en brugerdefineret logik for lighed, er det ikke nok kun at overskrive .Equals(). For at sikre forudsigelig og korrekt opførsel, især når dine objekter bruges i samlinger som Dictionary eller HashSet, skal du implementere en treenighed af metoder, der er konsistente med hinanden.

  1. Overskriv .Equals(Object obj): Definerer, hvad det vil sige for to objekter af din type at være "ens".
  2. Overskriv GetHashCode(): Denne metode skal returnere en integer-værdi. Reglen er simpel, men altafgørende: Hvis to objekter er ens ifølge .Equals(), skal de returnere den samme hash-kode.
  3. Overlæs operator == og operator !=: For at give en komplet og intuitiv brugeroplevelse, bør du også levere en statisk implementering af lighedsoperatorerne, der typisk bare kalder din .Equals() logik.

Hvorfor er GetHashCode så vigtig?

Samlinger som Dictionary<TKey, TValue> bruger hash-koder til hurtigt at finde elementer. Først beregner den nøglens hash-kode for at finde den rigtige "spand" (bucket), hvor elementet skulle være. Derefter bruger den .Equals() til at finde det præcise element blandt de få, der måtte være i den spand. Hvis GetHashCode og .Equals() er inkonsistente, vil samlingen opføre sig bizart. Et objekt kan måske ikke findes, selvom det er blevet tilføjet.

Lad os se på et eksempel med en dårligt implementeret Person struct:

struct Person { public int Age { get; set; } public string Name { get; set; } // Ligestilling er baseret på navnet public override bool Equals(Object obj) { return (obj is Person) && ((Person)obj).Name == Name; } // DÅRLIG IMPLEMENTERING: Hash-koden er baseret på alderen! public override int GetHashCode() { return Age; } } 

Hvis vi bruger denne struct i en dictionary, opstår der kaos:

var favColours = new Dictionary<Person, string>(); var p = new Person() { Age = 25, Name = "Alice" }; favColours[p] = "Blå"; // Alice har fødselsdag, hendes alder ændres p.Age = 26; // Vi prøver at finde Alices yndlingsfarve igen // Dictionary beregner ny hash-kode baseret på alder=26 og finder intet! bool found = favColours.ContainsKey(p); // found er false! 

Selvom objektet for "Alice" stadig er i dictionary'en, kan den ikke findes, fordi dens hash-kode har ændret sig. Dette illustrerer, hvorfor konsistens er altafgørende.

Sammenligningstabel: `==` vs. `.Equals()`

Egenskab== Operator.Equals() Metode
TypeOperator (statisk binding)Virtuel metode (dynamisk binding)
Standard for VærdityperSammenligner værdierSammenligner værdier
Standard for ReferencetyperSammenligner reference (hukommelsesadresse)Sammenligner reference (hukommelsesadresse)
Kan overskrives/overlæsses?Ja, kan overlæsses (f.eks. i string)Ja, kan overskrives (virtuel)
Håndtering af nullSikker. (null == null) er true.Usikker. null.Equals(obj) kaster en exception.
Bedst tilHurtige sammenligninger af værdityper og når man specifikt vil tjekke for reference-lighed.Polymorfisk sammenligning af værdi-lighed for klasser, der har overskrevet metoden.

Ofte Stillede Spørgsmål (OSS)

Hvad er den sikreste måde at sammenligne to strenge på, der kan være `null`?

Den absolut sikreste metode er at bruge den statiske string.Equals(). Den håndterer alle null-scenarier uden at kaste exceptions. For eksempel vil string.Equals(null, null) returnere true, og string.Equals("a", null) vil returnere false.

Hvorfor returnerer `(object)s1 == s2` `false`, selvom strengene er identiske?

Fordi == operatoren er statisk bundet. Når du caster den ene streng til object, tvinger du compileren til at bruge System.Object's standard == operator, som sammenligner referencer, ikke den specialiserede string-version, der sammenligner indhold.

Skal jeg altid overskrive `GetHashCode`, når jeg overskriver `Equals`?

Ja, uden undtagelse. Hvis du ikke gør det, vil dine objekter opføre sig ukorrekt og uforudsigeligt, når de bruges som nøgler i hash-baserede samlinger som Dictionary og HashSet, hvilket kan føre til meget svære at finde fejl i din kode.

Hvad er forskellen mellem `object.Equals(a, b)` og `a.Equals(b)`?

object.Equals(a, b) er en statisk hjælpe-metode. Den er smart, fordi den først tjekker for null. Hvis begge er null, returnerer den true. Hvis kun en er null, returnerer den false. Først hvis ingen af dem er null, kalder den a.Equals(b). Den er derfor en mere robust og null-sikker version af instans-metoden.

Hvis du vil læse andre artikler, der ligner C# Ligestilling: == vs. Equals() Forklaret, kan du besøge kategorien Sundhed.

Go up