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
lub short
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 a short
i an int
, short
zostanie ono domyślnie przekonwertowane na an int
. Jeśli jego wartość liczbowa była równa wartości, wartość int
, na int
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ą z int
jedyną niejawną konwersją, która zaspokoi przeciążenie Equals
metody, będzie konwersja na typ obiektu odpowiadający int
. Kiedy short
zapyta się, czy pasuje do przekazanego obiektu, zauważy, że przedmiotowy przedmiot jest int
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
int i = 16777217;
float f = 16777216.0f;
Console.WriteLine("{0}", i==f);
Istnieją trzy sposoby porównywania int
z float
. Można chcieć wiedzieć:
- Czy najbliższa możliwa
float
wartość int
odpowiada wartości float
?
- Czy część z liczbą całkowitą
float
pasuje do int
?
- Wykonaj
int
i float
reprezentuj tę samą wartość liczbową.
Jeśli ktoś próbuje porównać int
i float
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 typu System.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śli T
jest typem odniesienia, a x
jest to T
, to odniesienie typu T
powinno być w stanie się odnosić x
. Zatem, jeśli zmienna v
typu Int32
zawiera an Object
, odwołanie do typu Object
powinno być w stanie pomieścić odwołanie do v
lub jego zawartość. W rzeczywistości odniesienie typu Object
byłoby w stanie wskazać obiekt zawierający dane skopiowane v
, ale nie do v
siebie ani do jego zawartości. To by sugerowało, że żadne z nichv
ani jego zawartość nie jest tak naprawdę Object
.