Mam warunek w aplikacji silverlight, która porównuje 2 łańcuchy, z jakiegoś powodu, gdy ==
go używam , zwraca false, a .Equals()
zwraca true .
Oto kod:
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
// Execute code
}
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
// Execute code
}
Masz powód, dlaczego tak się dzieje?
==
, ale operatory nie są polimorficzne. W tym kodzie==
operator jest wywoływany według typuobject
, który dokonuje porównania tożsamości zamiast wartości.==
przeciążenie na podstawie typu argumentów czasu kompilacji.Content
Nieruchomośćobject
. Operatory nie są wirtualne, więc==
wywoływana jest domyślna implementacja , dająca porównanie równości odniesienia. W przypadku Equals wywołanie przechodzi do metody wirtualnejobject.Equals(object)
;string
przesłania tę metodę i wykonuje porządkowe porównanie zawartości ciągu. Zobacz msdn.microsoft.com/en-us/library/fkfd9eh8(v=vs.110).aspx i referenceource.microsoft.com/#mscorlib/system/string.cs,507 .==
ma typ czasu kompilacji,object
a prawa strona ma typ czasu kompilacjistring
, wówczas kompilator C # musi wybrać (problematyczne, w tym przypadku) przeciążenieoperator ==(object, object)
; ale to będzie wydawać ostrzeżenia w czasie kompilacji, że może to być niezamierzona. Przeczytaj więc ostrzeżenia dotyczące czasu kompilacji! Aby rozwiązać problem i nadal używać==
, przesuń lewą stronę nastring
. Jeśli dobrze pamiętam, tekst ostrzegawczy sugeruje właśnie to.Odpowiedzi:
Kiedy
==
zostanie użyty do wyrażenia typuobject
, rozpoznaSystem.Object.ReferenceEquals
.Equals
jest tylkovirtual
metodą i zachowuje się jako taka, więc zostanie użyta przesłonięta wersja (która dlastring
typu porównuje zawartość).źródło
object
pismo (zwróć uwagę na czcionkę monospace) technicznie ma być „wyrażeniem typuSystem.Object
”. Nie ma to nic wspólnego z typem wykonawczym instancji, do której odwołuje się wyrażenie. Myślę, że stwierdzenie „operatory zdefiniowane przez użytkownika są traktowane jakvirtual
metody” jest bardzo mylące. Są one traktowane jak przeciążone metody i zależą tylko od typu argumentów w czasie kompilacji. W rzeczywistości, po obliczeniu zbioru kandydujących operatorów zdefiniowanych przez użytkownika, resztą procedury wiązania będzie dokładnie algorytm rozstrzygania przeciążenia metodyvirtual
rozdzielczość metody zależy od faktycznego typu środowiska wykonawczego instancji, podczas gdy jest to całkowicie ignorowane w rozwiązaniu przeciążenia operatora, i to jest właśnie sedno mojej odpowiedzi.Podczas porównywania odwołania do obiektu do łańcucha (nawet jeśli odwołanie do obiektu odnosi się do łańcucha), specjalne zachowanie
==
operatora specyficzne dla klasy łańcucha jest ignorowane.Zwykle (gdy nie ma do czynienia z łańcuchami),
Equals
porównuje wartości , a==
porównuje odwołania do obiektów . Jeśli dwa porównywane obiekty odnoszą się do tej samej dokładnej instancji obiektu, wówczas oba zwrócą wartość true, ale jeśli jeden ma tę samą treść i pochodzi z innego źródła (jest osobną instancją z tymi samymi danymi), tylko równa się zwróć prawdę. Jednak, jak zauważono w komentarzach, ciąg znaków jest szczególnym przypadkiem, ponieważ przesłania==
operator, tak więc w przypadku czysto odwołań do ciągów (a nie odwołań do obiektów) porównywane są tylko wartości, nawet jeśli są to osobne wystąpienia. Poniższy kod ilustruje subtelne różnice w zachowaniach:Dane wyjściowe to:
źródło
==
i.Equals
oba są zależne od zachowania określonego w rzeczywistym typie i rzeczywistym typie w miejscu połączenia. Obie są tylko metodami / operatorami, które można zastąpić dowolnym rodzajem i biorąc pod uwagę dowolne zachowanie, które autor sobie zażyczy. Z mojego doświadczenia wynika, że ludzie często implementują.Equals
na obiekcie, ale zaniedbują implementację operatora==
. Oznacza to, że.Equals
faktycznie będzie mierzyć równość wartości podczas==
sprawdzi, czy są one tym samym odniesieniem.Kiedy pracuję z nowym typem, którego definicja jest zmienna lub piszę ogólne algorytmy, uważam, że najlepsza praktyka jest następująca
Object.ReferenceEquals
bezpośrednio (nie jest to konieczne w przypadku ogólnym)EqualityComparer<T>.Default
W niektórych przypadkach, gdy uważam, że użycie
==
jest niejednoznaczne, jawnieObject.Reference
użyję znaku równości w kodzie, aby usunąć niejednoznaczność.Eric Lippert niedawno napisał post na blogu na temat tego, dlaczego istnieją 2 metody równości w CLR. Warto przeczytać
źródło
== Operator
.Równa się
źródło
==
Operator może być przeciążony dla każdego rodzaju, nie tylko strun. Opisanie wyjątku specjalnego przypadku tylko dla ciągu znaków wprowadza w błąd semantykę operatora. Bardziej dokładne, choć być może nie byłoby szczególnie użyteczne, byłoby powiedzenie „jeśli operandy są typami referencyjnymi, zwraca wartość true, jeśli operandy odnoszą się do tego samego obiektu, chyba że występuje odpowiednie przeciążenie, w którym to przypadku implementacja tego przeciążenia określa wynik „. To samo dotyczyEquals
dodanej komplikacji, że jest to metoda wirtualna, więc jej zachowanie może być nadpisane, a także przeciążone.Po pierwsze, jest różnica. Dla liczb
I na smyczki
W obu przypadkach
==
zachowuje się bardziej użytecznie niż.Equals
źródło
==
operatorem za dobrą rzecz. Na przykład, czy 16777216.0f powinno być równe (int) 16777217, (podwójne) 16777217.0, oba, czy żadne? Porównania między typami całkowymi są w porządku, ale porównania zmiennoprzecinkowe powinny być wykonywane tylko IMHO z wartościami, które są jawnie rzutowane na pasujące typy. Porównanie afloat
do czegoś innego niż afloat
, lubdouble
do czegoś innego niż adouble
, uderza mnie jako główny zapach kodu, który nie powinien się kompilować bez diagnozy.x == y
nie oznaczax/3 == y/3
(spróbujx = 5
iy = 5.0
)./
dzielenia liczb całkowitych jest wadą w projektowaniu C # i Java. Pascal,div
a nawet VB.NET` are much better. The problems with
== `są jednak gorsze:x==y
iy==z
nie implikuje tegox==z
(rozważ trzy liczby w moim poprzednim komentarzu). Co do relacji sugerujesz, nawet jeślix
iy
to zarównofloat
albo obadouble
,x.equals((Object)y)
nie oznacza, że1.0f/x ==
1.0f / y` (jeśli miałem druthers, byłoby zagwarantować, że, nawet jeśli==
nie odróżnia pozytywne i zero,Equals
powinny).O ile rozumiem odpowiedź jest prosta:
==
porównuje odwołania do obiektów..Equals
porównuje zawartość obiektu.String
typy danych zawsze działają jak porównanie zawartości.Mam nadzieję, że mam rację i że odpowiedział na twoje pytanie.
źródło
Dodałbym, że jeśli rzutujesz swój obiekt na ciąg, to zadziała on poprawnie. Dlatego kompilator wyświetli ostrzeżenie:
źródło
object expr = XXX; if (expr == "Energy") { ... }
, to skoro lewa strona ma czas kompilacjiobject
, kompilator musi użyć przeciążeniaoperator ==(object, object)
. Sprawdza równość odniesienia. Czy da to,true
czyfalse
może być trudne do przewidzenia z powodu internowania łańcucha . Jeśli wiesz, że lewa strona jest albonull
typustring
, rzuć lewą stronę nastring
przed użyciem==
.Ponieważ do
.Equal
tej pory nie wspomniano o statycznej wersji metody, chciałbym dodać ją tutaj, aby podsumować i porównać 3 warianty.gdzie
MyString
jest zmienną pochodzącą z innego miejsca w kodzie.Informacje w tle i na lato:
W Javie
==
do porównywania łańcuchów nie należy używać. Wspominam o tym na wypadek, gdybyś musiał używać obu języków, a także poinformować, że używanie==
można również zastąpić czymś lepszym w języku C #.W języku C # nie ma praktycznej różnicy w porównywaniu ciągów przy użyciu metody 1 lub metody 2, o ile oba są ciągami typu. Jednakże, jeśli jeden jest pusty, jeden jest innego typu (np. Liczba całkowita) lub jeden reprezentuje obiekt, który ma inne odwołanie, wówczas, jak pokazuje początkowe pytanie, możesz doświadczyć, że porównanie zawartości dla równości może nie zwrócić tego, co oczekujesz.
Sugerowane rozwiązanie:
Ponieważ używanie
==
nie jest dokładnie tym samym, co używanie.Equals
podczas porównywania rzeczy, można zamiast tego użyć statycznej metody String.Equals . W ten sposób, jeśli dwie strony nie są tego samego typu, nadal będziesz porównywać zawartość, a jeśli jedna będzie pusta, unikniesz wyjątku.Jest trochę więcej do napisania, ale moim zdaniem bezpieczniejszy w użyciu.
Oto niektóre informacje skopiowane z Microsoft:
Parametry
a
StrunowyPierwszy ciąg do porównania lub
null
.b
StrunowyDrugi ciąg do porównania, lub
null
.Zwroty
Boolean
true
jeśli wartośća
jest taka sama jak wartośćb
; w przeciwnym raziefalse
. Jeśli oba sąa
i , metoda zwraca .b
null
true
źródło
Tylko jako uzupełnienie już dobrych odpowiedzi: To zachowanie NIE jest ograniczone do ciągów znaków lub porównywania różnych typów liczb. Nawet jeśli oba elementy są typu obiektu tego samego typu bazowego. „==” nie będzie działać.
Poniższy zrzut ekranu pokazuje wyniki porównania dwóch wartości obiektu {int}
źródło
Jestem tu trochę zdezorientowany. Jeśli typ środowiska wykonawczego Content ma ciąg znaków, zarówno ==, jak i Equals powinny zwracać wartość true. Ponieważ jednak nie wydaje się, że tak się dzieje, typ zawartości w środowisku wykonawczym nie jest ciągiem, a wywołanie na nim równości powoduje równość referencyjną, co wyjaśnia, dlaczego zawodzi równość („atak energii”). Jednak w drugim przypadku decyzja, który przeciążony operator == statyczny powinien zostać wywołany, jest podejmowana w czasie kompilacji i wydaje się, że ta decyzja to == (ciąg, ciąg). sugeruje mi to, że Treść zapewnia niejawną konwersję na ciąg znaków.
źródło
Istnieje inny wymiar wcześniejszej odpowiedzi @BlueMonkMN. Dodatkowym wymiarem jest to, że odpowiedź na pytanie tytułowe @ Drahcir, jak zostało powiedziane, zależy również od tego , jak doszliśmy do tej
string
wartości. Ilustrować:Dane wyjściowe to:
źródło
Dodanie jeszcze jednego punktu do odpowiedzi.
.EqualsTo()
ta metoda zapewnia porównanie z kulturą i rozróżnianiem wielkości liter.źródło
==
Żeton w C # jest używany dla dwóch różnych operatorów równości sprawdzić. Gdy kompilator napotka ten token, sprawdzi, czy którykolwiek z porównywanych typów zaimplementował przeciążenie operatora równości albo dla konkretnych typów kombinacji, które są porównywane (*), czy dla kombinacji typów, na które oba typy mogą być przekształcone. Jeśli kompilator znajdzie takie przeciążenie, użyje go. W przeciwnym razie, jeśli oba typy są typami referencyjnymi i nie są klasami niepowiązanymi (może to być interfejs lub mogą to być klasy pokrewne), kompilator uwzględni==
jako operator porównania referencji. Jeśli żaden warunek nie zostanie spełniony, kompilacja się nie powiedzie.Zauważ, że niektóre inne języki używają osobnych tokenów dla dwóch operatorów kontroli równości. Na przykład w VB.NET
=
token jest używany w wyrażeniach wyłącznie dla przeciążalnego operatora sprawdzania równości iIs
jest używany jako test odniesienia lub operator testu zerowego. Zastosowanie=
typu, który nie zastępuje operatora sprawdzania równości, zakończy się niepowodzeniem, podobnie jak próba użyciaIs
w celu innym niż testowanie równości lub nieważności odniesienia.(*) Typy zazwyczaj przeciążają równość tylko w celu porównania ze sobą, ale może być przydatne dla typów w celu przeciążenia operatora równości w celu porównania z innymi konkretnymi typami; na przykład
int
mógł (i IMHO powinien, ale nie zdefiniował) zdefiniować operatory równości do porównaniafloat
, tak aby 16777217 nie zgłosiłby się jako równy 16777216f. Ponieważ tak się nie dzieje, ponieważ żaden taki operator nie jest zdefiniowany, C # będzie promowaćint
tofloat
, zaokrąglając go do 16777216f, zanim operator kontroli równości zobaczy go; operator ten widzi następnie dwie równe liczby zmiennoprzecinkowe i zgłasza je jako równe, nieświadomy zaokrąglenia, które miało miejsce.źródło
3
jako równe3.0f
. Jeśli wymagamy od programisty, aby powiedział, co jest zamierzone w każdym przypadku, nie ma niebezpieczeństwa domyślnego zachowania prowadzącego do niezamierzonych rezultatów, ponieważ nie ma domyślnego zachowania.Naprawdę świetne odpowiedzi i przykłady!
Chciałbym tylko dodać podstawową różnicę między nimi,
Mając na uwadze tę koncepcję, jeśli opracujesz dowolny przykład (patrząc na typ odniesienia lewej i prawej ręki oraz sprawdzając / wiedząc, czy typ rzeczywiście ma przeciążony operator == i jest zastępowany równy), na pewno otrzymasz właściwą odpowiedź .
źródło
Kiedy tworzymy dowolny obiekt, mamy do czynienia z dwiema częściami, z których jedna stanowi treść, a druga jest odniesieniem do tej treści.
==
porównuje zarówno treść, jak i referencje;equals()
porównuje tylko treśćhttp://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq
źródło
a
ib
oba są odwołaniami do łańcucha, wynika == b
nie zależy od tego, czy odwołania wskazują na ten sam obiekt.==
Operator == może być użyty do porównania dwóch zmiennych dowolnego rodzaju i po prostu porównuje bity .
Uwaga: po lewej stronie int jest więcej zer, ale tutaj nas to nie obchodzi.
int a (00000011) == bajt b (00000011)
Pamiętaj = = operator dba tylko o wzór bitów w zmiennej.
Użyj == Jeśli dwa odwołania (prymitywy) odnoszą się do tego samego obiektu na stercie.
Reguły są takie same, niezależnie od tego, czy zmienna jest odwołaniem, czy prymitywem.
a == c jest prawdą a == b jest fałszem
wzór bitowy jest taki sam dla a i c, więc są one równe przy użyciu ==.
Równy():
Użyj metody equals (), aby sprawdzić, czy dwa różne obiekty są równe .
Takich jak dwa różne obiekty String, które reprezentują znaki w „Jane”
źródło
object a = 3; object b = 3; Console.WriteLine(a == b);
. Dane wyjściowe są fałszywe, mimo że wzorce bitowe wartości są takie same. Liczą się także typy operandów. Powodem, dla którego „nie przejmujemy się” inną liczbą zer w twoim przykładzie jest to, że do czasu wywołania operatora równości liczba zer jest w rzeczywistości taka sama , z powodu niejawnej konwersji.Jedyna różnica między Equal i == polega na porównaniu typów obiektów. w innych przypadkach, takich jak typy referencyjne i typy wartości, są one prawie takie same (oba są równe bitowo lub oba są równe referencyjne).
obiekt: Równa się: równość bitowa ==: równość odniesienia
string: (równe i == są takie same dla ciągu, ale jeśli jeden z ciągów zostanie zmieniony na obiekt, wynik porównania będzie inny) Równa się: równość bitowa ==: równość bitowa
Zobacz tutaj , aby uzyskać więcej wyjaśnień.
źródło