Rozważ ten kod:
int age = 25;
short newAge = 25;
Console.WriteLine(age == newAge); //true
Console.WriteLine(newAge.Equals(age)); //false
Console.ReadLine();
Zarówno int
i short
są prymitywne typy, ale porównanie z ==
Zwraca true i porównanie z Equals
zwraca false.
Czemu?
Console.WriteLine(age.Equals(newAge));
Equals()
ogólnie.Odpowiedzi:
Krótka odpowiedź:
Równość jest skomplikowana.
Szczegółowa odpowiedź:
Typy operacji podstawowych zastępują bazę
object.Equals(object)
i zwracają wartość true, jeśli poleobject
jest tego samego typu i wartości. (Należy pamiętać, że będzie to również działać dla typów zerowalnych; typy zerowe zerowalne zawsze są zaznaczone dla instancji typu bazowego).Ponieważ
newAge
jest toshort
, jegoEquals(object)
metoda zwraca wartość true tylko wtedy, gdy przekażesz krótkie pole o tej samej wartości. Podajesz pudełkoint
, więc zwraca wartość false.Natomiast
==
operator definiuje się jako przyjmowanie dwóchint
s (lubshort
s lublong
s).Po wywołaniu go za pomocą
int
aishort
kompilator domyślnie przekonwertuje wartośćshort
naint
i porówna wynikoweint
wartości s.Inne sposoby, aby to działało
Typy pierwotne mają również własną
Equals()
metodę, która akceptuje ten sam typ.Jeśli napiszesz
age.Equals(newAge)
, kompilator wybierzeint.Equals(int)
najlepsze przeciążenie i domyślnie przekonwertujeshort
naint
. Następnie powrócitrue
, ponieważ ta metoda po prostu porównujeint
s bezpośrednio.short
ma równieżshort.Equals(short)
metodę, aleint
nie można jej niejawnie przekonwertowaćshort
, więc jej nie wywołujesz.Możesz zmusić go do wywołania tej metody za pomocą obsady:
To zadzwoni
short.Equals(short)
bezpośrednio, bez boksu. Jeśliage
jest większy niż 32767, wygeneruje wyjątek przepełnienia.Można również wywołać
short.Equals(object)
przeciążenie, ale jawnie przekazać obiekt w ramce, aby uzyskał ten sam typ:Podobnie jak poprzednia alternatywa, spowoduje to przepełnienie, jeśli nie pasuje do
short
. W przeciwieństwie do poprzedniego rozwiązania umieści goshort
w obiekcie, marnując czas i pamięć.Kod źródłowy:
Oto obie
Equals()
metody z rzeczywistego kodu źródłowego:Dalsza lektura:
Zobacz Eric Lippert .
źródło
long == int
,int
domyślnie przekonwertowane nalong
prawo?int age = 25;
sięconst int age = 25;
, wtedy wynik będzie się zmieniać. Jest tak, ponieważ w tym przypadku istnieje domniemana konwersja zint
nashort
. Zobacz Implikowane konwersje wyrażeń stałych .==
operator porównuje typy referencyjne przez odniesienie. W przypadku typów wartości i typów, które przeciążają==
, nie działa.Ponieważ nie ma przeciążenia,
short.Equals
które akceptujeint
. Dlatego nazywa się to:obj
nie jestshort
… dlatego jest fałszywe.źródło
Kiedy przechodzisz
int
doshort
's Equals, przekazujeszobject
:Działa więc ten pseudokod:
źródło
W przypadku typów wartości
.Equals
wymaga , aby dwa obiekty były tego samego typu i miały tę samą wartość, a==
jedynie sprawdza, czy te dwie wartości są takie same.Object.Equals
http://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx
źródło
==
służy do sprawdzania równego warunku, może być traktowany jako operator (operator logiczny), po prostu do porównania 2 rzeczy, a tutaj typ danych nie ma znaczenia, ponieważ wykonano by rzutowanie typu iEquals
jest również używany do sprawdzania równego warunku , ale w tym przypadku typy danych powinny być takie same. N Równa się to metoda, a nie operator.Poniżej znajduje się mały przykład wzięty z tego, który podałeś, i to w skrócie wyjaśni różnicę.
w powyższym przykładzie X i Y mają takie same wartości, tj. 1, a gdy użyjemy
==
, zwróci true, tak jak w przypadku==
, krótki typ jest konwertowany na int przez kompilator i wynik jest podawany.a kiedy używamy
Equals
, porównywanie jest zakończone, ale rzutowanie typu nie jest wykonywane przez kompilator, więc zwracane jest false.Chłopaki, dajcie znać, jeśli się mylę.
źródło
W wielu kontekstach, w których argument metody lub operatora nie jest wymaganego typu, kompilator C # będzie próbował przeprowadzić niejawną konwersję typu. Jeśli kompilator może sprawić, że wszystkie argumenty spełniają ich operatory i metody poprzez dodanie niejawnych konwersji, zrobi to bez zarzutu, nawet jeśli w niektórych przypadkach (szczególnie z testami równości!) Wyniki mogą być zaskakujące.
Ponadto, każdy typ wartości taki jak
int
lubshort
faktycznie opisuje zarówno rodzaj wartości, jak i rodzaj obiektu (*). Istnieją niejawne konwersje w celu konwersji wartości na inne rodzaje wartości oraz w celu konwersji dowolnego rodzaju wartości na odpowiadający mu rodzaj obiektu, ale różne rodzaje obiektów nie są wzajemnie konwertowalne.Jeśli użyje się
==
operatora do porównania ashort
i anint
,short
zostanie ono domyślnie przekonwertowane na anint
. Jeśli jego wartość liczbowa była równa wartości, wartośćint
, naint
którą został przeliczony, będzie równa wartości,int
z którą jest porównywany. Jeśli jednak spróbujemy użyćEquals
metody w skrócie, aby porównać ją zint
jedyną niejawną konwersją, która zaspokoi przeciążenieEquals
metody, będzie konwersja na typ obiektu odpowiadającyint
. Kiedyshort
zapyta się, czy pasuje do przekazanego obiektu, zauważy, że przedmiotowy przedmiot jestint
raczej znakiem a niżshort
a, co oznacza, że nie może być równy.Ogólnie rzecz biorąc, chociaż kompilator nie będzie na to narzekać, należy unikać porównywania rzeczy, które nie są tego samego typu; jeśli ktoś jest zainteresowany tym, czy konwersja rzeczy do wspólnej formy dałaby ten sam wynik, należy taką konwersję wykonać jawnie. Zastanów się na przykład
Istnieją trzy sposoby porównywania
int
zfloat
. Można chcieć wiedzieć:float
wartośćint
odpowiada wartościfloat
?float
pasuje doint
?int
ifloat
reprezentuj tę samą wartość liczbową.Jeśli ktoś próbuje porównać
int
ifloat
bezpośrednio, skompilowany kod będzie odpowiedzieć na pierwsze pytanie; czy tego właśnie zamierzał programista, nie będzie to jednak oczywiste. Zmiana porównania na(float)i == f
wyjaśni, że pierwsze znaczenie było zamierzone, lub(double)i == (double)f
spowoduje, że kod odpowie na trzecie pytanie (i wyjaśni, że to było zamierzone).(*) Nawet jeśli specyfikacja C # traktuje wartość typu np.
System.Int32
Jako obiekt typuSystem.Int32
, temu poglądowi zaprzecza wymóg, aby kod działał na platformie, której specyfikacja traktuje wartości i obiekty jako zamieszkujące różne wszechświaty. Ponadto, jeśliT
jest typem odniesienia, ax
jest toT
, to odniesienie typuT
powinno być w stanie się odnosićx
. Zatem, jeśli zmiennav
typuInt32
zawiera anObject
, odwołanie do typuObject
powinno być w stanie pomieścić odwołanie dov
lub jego zawartość. W rzeczywistości odniesienie typuObject
byłoby w stanie wskazać obiekt zawierający dane skopiowanev
, ale nie dov
siebie ani do jego zawartości. To by sugerowało, że żadne z nichv
ani jego zawartość nie jest tak naprawdęObject
.źródło
the only implicit conversion which would satisfy an overload of the Equals method would be the conversion to the object type corresponding to int
Źle. W przeciwieństwie do Java, C # nie ma oddzielnych typów pierwotnych i pudełkowych. Jest zapakowane,object
ponieważ jest to jedyne inne przeciążenieEquals()
.float
. Rzutfloat
na adouble
nie magicznie stworzy nową precyzję.List<String>.Enumerator
i obiektu sterty typuList<String>.Enumerator
są takie same, ale specyfikacja ECMA / CLI mówi, że są różne, a nawet gdy są używane w C #, zachowują się inaczej.i
if
zostałyby przekonwertowanedouble
przed porównaniem, otrzymałyby 16777217.0 i 16777216.0, które są porównywane jako nierówne. Konwersjai
float
dałoby 16777216.0f, w porównaniu równa sięf
.bool SelfSame<T>(T p) { return Object.ReferenceEquals((Object)p,(Object)p);}
. Typ obiektu w ramce odpowiadający typowi wartości może spełniać typ parametruReferenceEquals
poprzez upcast zachowujący tożsamość ; typ lokalizacji magazynu wymaga jednak konwersji nieobsługującej tożsamości . Jeśli odlewaniaT
doU
rentowności odniesienie do czegoś innego niż oryginałT
, który sugerował mi się, żeT
tak naprawdę nie jestU
.Equals () jest metodą System.Object klasy
składni: wirtualne równi public bool ()
Zalecenie jeśli chcemy porównać stan dwóch obiektów wówczas powinniśmy użyć equals () metodę
jak podano powyżej odpowiedzi == operatorzy porównują wartości są takie same.
Proszę się nie mylić z ReferenceEqual
Reference Equals ()
Składnia: public static bool ReferenceEquals ()
Określa, czy określona instancja obiektów jest tej samej instancji
źródło
Musisz zdać sobie sprawę z tego, że działanie
==
zawsze kończy się wywołaniem metody. Pytanie brzmi, czy dzwonienie==
iEquals
kończy dzwonienie / robienie tych samych rzeczy.W przypadku typów referencyjnych
==
zawsze 1. sprawdza, czy referencje są takie same (Object.ReferenceEquals
).Equals
z drugiej strony może zostać zastąpione i może sprawdzić, czy niektóre wartości są równe.EDYCJA: aby odpowiedzieć svick i dodać komentarz SLaks, oto trochę kodu IL
źródło
int
s z wywołaniem ==? Wskazówka: nie maoperator ==
metody dlaInt32
, ale jest jedna dlaString
.==
nie tylko robi magię, ale w końcu po prostu wywołuje metodę (większość programistów prawdopodobnie nigdy nie wdrożyła / nie zastąpiła żadnego operatora). Może mógłbym dodać komentarz do twojego pytania zamiast własnej odpowiedzi. Zaktualizuj swój, jeśli uważasz, że to, co powiedziałem, jest istotne.==
w typach pierwotnych nie jest przeciążonym operatorem, ale właściwością języka wewnętrznego, która kompiluje się zceq
instrukcją IL.== W prymitywnych
W pierwotnym porównaniu operator == zachowuje się dość oczywisto, w języku C # dostępnych jest wiele przeciążeń operatora ==.
Zatem w tym przypadku nie jest możliwa domyślna konwersja z
int
na,short
aleshort
naint
możliwa. Więc newAge jest konwertowany na int i następuje porównanie, które zwraca true, ponieważ oba mają tę samą wartość. Jest to więc równoważne z:.Equals () w Primitive
Tutaj musimy zobaczyć, co to jest metoda Equals (), nazywamy Equals zmienną krótkiego typu. Istnieją więc trzy możliwości:
Pierwszy typ nie ma tu znaczenia, ponieważ liczba argumentów jest inna, wywołujemy tylko jednym argumentem typu int. Trzeci również został wyeliminowany, jak wspomniano powyżej, nie jest możliwa domniemana konwersja int na short. Więc tutaj
Equals(object)
nazywany jest drugi typ . Jestshort.Equals(object)
to:Więc tutaj sprawdzono warunek,
z is short
który jest fałszywy, ponieważ z jest int, więc zwraca false.Oto szczegółowy artykuł Erica Lipperta
źródło