Poniższe działania spowodują nieskończoną rekursję w metodzie przeciążenia operatora ==
Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);
public static bool operator ==(Foo foo1, Foo foo2) {
if (foo1 == null) return foo2 == null;
return foo1.Equals(foo2);
}
Jak sprawdzić wartości null?
c#
.net
operator-overloading
Andrew Jones
źródło
źródło
Assert.IsFalse(foo2 == foo1);
foo1.Equals(foo2)
znaczy, jeśli na przykład chcęfoo1 == foo2
tylko wtedyfoo1.x == foo2.x && foo1.y == foo2.y
? Czy to nie odpowiada ignorując przypadek, gdzie,foo1 != null
alefoo2 == null
?if (foo1 is null) return foo2 is null;
Rzutowanie na obiekt w metodzie przeciążenia:
źródło
(object)foo1 == null
lubfoo1 == (object)null
przejdą do wbudowanego przeciążenia,==(object, object)
a nie do przeciążenia zdefiniowanego przez użytkownika==(Foo, Foo)
. To jest tak, jak w przypadku rozwiązywania przeciążeń metod.Użyj
ReferenceEquals
. Z forów MSDN :źródło
Próbować
Object.ReferenceEquals(foo1, null)
W każdym razie nie polecałbym przeciążania
==
operatora; Powinien być używany do porównywania odniesień iEquals
do porównań „semantycznych”.źródło
Jeśli nadpisałem
bool Equals(object obj)
i chcę, aby operator==
iFoo.Equals(object obj)
zwracał tę samą wartość, zwykle implementuję!=
operator w ten sposób:Operator
==
po wykonaniu wszystkich sprawdzeń zerowych zakończy się dla mnie wywołaniemfoo1.Equals(foo2)
, że przesłoniłem, aby wykonać faktyczne sprawdzenie, czy oba są równe.źródło
Object.Equals(Object, Object)
obok siebieObject.ReferenceEquals(Object, Object)
, jest całkiem jasne, żeObject.Equals(Object, Object)
robi wszystko, co sugerowano w innych odpowiedziach po wyjęciu z pudełka. Dlaczego tego nie używać?==
operatora, jeśli chcesz tylko domyślnego zachowania. Należy przeciążać tylko wtedy, gdy trzeba zaimplementować niestandardową logikę porównania, czyli coś więcej niż sprawdzanie równości odwołań.==
jest pożądane (pytanie to sugeruje), po prostu popieram tę odpowiedź, sugerując,Object.Equals(Object, Object)
że inne sztuczki, takie jak używanieReferenceEquals
lub jawne rzucanie, są niepotrzebne (a więc „dlaczego nie użyć tego?”, „to”) istnienieEquals(Object, Object)
). Nawet jeśli niepowiązany twój punkt widzenia jest również poprawny i poszedłbym dalej: przeciążenie tylko==
obiektów, które możemy sklasyfikować jako „obiekty wartościowe”.Object.Equals(Object, Object)
z kolei wywołuje Object.Equals (Object), który jest metodą wirtualną, którą Foo prawdopodobnie zastępuje. Fakt, że wprowadziłeś wirtualne wywołanie do sprawdzania równości, może wpłynąć na zdolność kompilatora do optymalizacji (np. Inline) tych wywołań. W większości przypadków jest to prawdopodobnie nieistotne, ale w niektórych przypadkach niewielki koszt operatora równości może oznaczać ogromny koszt pętli lub posortowanych struktur danych.Jeśli używasz języka C # 7 lub nowszego, możesz użyć stałego dopasowania wzorca o wartości null:
Daje to nieco schludniejszy kod niż ten wywołujący obiekt.ReferenceEquals (foo1, null)
źródło
public static bool operator==( Foo foo1, Foo foo2 ) => foo1?.Equals( foo2 ) ?? foo2 is null;
W
null
tym przypadku istnieje prostszy sposób sprawdzenia :Otóż to!
Ta funkcja została wprowadzona w języku C # 7
źródło
Moje podejście jest do zrobienia
na którym polegam na
object
własnym operatorze równości, który nie może się nie udać. Lub niestandardowa metoda rozszerzenia (i przeciążenie):lub aby obsłużyć więcej spraw, może być:
Ograniczenie zapobiega
IsNull
typom wartości. Teraz jest tak słodki jak dzwonienieco oznacza, że mam jeden spójny / nie podatny na błędy styl sprawdzania wartości null w całym tekście. Stwierdziłem również, że
(object)item == null
jest bardzo, bardzo, trochę szybszy niżObject.ReferenceEquals(item, null)
, ale tylko wtedy, gdy ma to znaczenie (obecnie pracuję nad czymś, w którym muszę wszystko mikro-optymalizować!).Aby zobaczyć kompletny przewodnik dotyczący wdrażania sprawdzania równości, zobacz „ Co to jest„ Najlepsza praktyka ”porównywania dwóch wystąpień typu odwołania?
źródło
DbNull
, IMO przypadki, w których nie generowałoby to problemów związanych z SRP, są dość rzadkie. Jednak samo wskazanie zapachu kodu może być bardzo odpowiednie.Statyczne
Equals(Object, Object)
metody wskazuje, czy dwa obiekty,objA
aobjB
są równe. Umożliwia także testowanie obiektów, których wartość dotyczynull
równości. PorównujeobjA
iobjB
dla równości w następujący sposób:true
. Ten test jest równoważny wywołaniuReferenceEquals
metody. Ponadto, jeśli obaobjA
iobjB
sąnull
, metoda zwracatrue
.objA
czyobjB
jestnull
. Jeśli tak, to wracafalse
. Jeśli te dwa obiekty nie reprezentują tego samego odwołania do obiektu i żadna z nich nie jestnull
, wywołujeobjA.Equals(objB)
i zwraca wynik. Oznacza to, że jeśliobjA
przesłaniaObject.Equals(Object)
metodę, to zastąpienie jest wywoływane..
źródło
odpowiadanie bardziej na przesłanianie operatora, jak porównać z null, który przekierowuje tutaj jako duplikat.
W przypadkach, w których robi się to w celu obsługi obiektów wartości, uważam, że nowa notacja jest przydatna i lubię upewnić się, że jest tylko jedno miejsce, w którym dokonuje się porównania. Wykorzystanie również Object.Equals (A, B) upraszcza sprawdzanie wartości null.
Spowoduje to przeciążenie ==,! =, Equals i GetHashCode
W przypadku bardziej skomplikowanych obiektów dodaj dodatkowe porównania w Equals i bogatszym GetHashCode.
źródło
Aby uzyskać nowoczesną i skondensowaną składnię:
źródło
Sprawdź to
odniesienia Wytyczne dotyczące przeciążania równa się () i operator ==
źródło
Możesz spróbować użyć właściwości obiektu i przechwycić wynikowy wyjątek NullReferenceException. Jeśli próbowana właściwość jest dziedziczona lub zastępowana przez Object, to działa to dla każdej klasy.
źródło