W C # 7 możemy użyć
if (x is null) return;
zamiast
if (x == null) return;
Czy są jakieś zalety korzystania z nowego sposobu (poprzedni przykład) w stosunku do starego?
Czy semantyka jest inna?
Czy to tylko kwestia gustu? Jeśli nie, to kiedy powinienem stosować jeden na drugim?
Odniesienie: Co nowego w C # 7.0 .
Odpowiedzi:
Aktualizacja: Kompilator Roslyn został zaktualizowany, aby zachowanie dwóch operatorów było takie samo, gdy nie ma przeciążonego operatora równości . Zobacz kod w bieżących wynikach kompilatora (
M1
iM2
w kodzie), który pokazuje, co się dzieje, gdy nie ma przeciążonego modułu porównującego równość. Obaj mają teraz lepsze wyniki==
. Jeśli istnieje przeciążony moduł porównujący równość, kod nadal się różni .Zobacz starsze wersje kompilatora Roslyn poniższą analizę.
Ponieważ
null
nie ma różnicy w stosunku do tego, do czego jesteśmy przyzwyczajeni w C # 6. Jednak rzeczy stają się interesujące, kiedy zmieniasznull
na inną stałą.Weźmy na przykład:
Test daje wynik
a
. Jeśli porównasz to zo == (object)1
tym, co napisałbyś normalnie, robi to cholerną różnicę.is
bierze pod uwagę typ po drugiej stronie porównania. To jest fajne!Myślę, że wzorzec
== null
vs.is null
stały jest po prostu czymś bardzo znanym „przypadkiem”, gdzie składniais
operatora i operatora równości daje ten sam wynik.Jak komentował svick ,
is null
połączenia sąSystem.Object::Equals(object, object)
tam==
ceq
, gdzie są połączenia .IL dla
is
:IL dla
==
:Ponieważ mówimy o tym
null
, nie ma różnicy, ponieważ wpływa to tylko na instancje . Może się to zmienić, gdy przeciążono operatora równości.źródło
is
wywołaniaobject.Equals(x, null)
, podczas gdy==
kompiluje jakoceq
. Ale wynik powinien być taki sam, jak powiedziałeś.==
operator jest przeciążalny. Możesz mieć z nim dowolne zachowanie. Na przykład dla tego dziwnie zaimplementowane==
nie powie ci, czy twoja instancja jest naprawdę zerowa.is null
z drugiej strony zawsze zwróci true dla prawdziwych referencji zerowych :) Ponadto, jeśli maszReferenceEquals
w swoim kodzie, żarówki VS 2017 zasugerują zmianę nais null
, nie== null
(poprawnie).is
nie ma już narzutu wywołania funkcji, gdy jest używany do sprawdzania wartości zerowej. Aby uzyskać dowód, zobacz link opublikowany przez @svick w komentarzach.Przeciążony jest równy operatorowi
W rzeczywistości istnieje różnica w semantyce między dwoma porównaniami, gdy porównujesz
null
z typem, który przeciążył==
operatora.foo is null
użyje bezpośredniego porównania referencyjnego w celu ustalenia wyniku, podczas gdyfoo == null
oczywiście uruchomi przeciążone==
operatora, jeśli taki istnieje.W tym przykładzie wprowadziłem „błąd” w przeciążonym
==
operatorze, powodując, że zawsze zgłasza wyjątek, jeśli drugi argument tonull
:Kod IL
foo is null
używaceq
instrukcji do bezpośredniego porównania odniesienia:Kod IL dla
foo == null
używa połączenia do przeciążonego operatora:Różnica polega na tym, że jeśli użyjesz
==
, ryzykujesz uruchomieniem kodu użytkownika (który może mieć nieoczekiwane problemy z zachowaniem lub wydajnością).Ograniczenia dotyczące leków generycznych
Użycie
is null
konstrukcji ogranicza typ do typu odwołania. Kompilator to zapewnia, co oznacza, że nie można użyćis null
typu wartości. Jeśli masz ogólną metodę, nie będziesz w stanie jej użyćis null
chyba że typ ogólny jest ograniczony do typu referencyjnego.Dzięki Davidowi Augusto Villa za zwrócenie na to uwagi.
źródło