To takie minimalne wprowadzenie - konwersje dzielą się na 'jawne'
(explicit) i 'niejawne'
(implicit).
Jawna konwersja musi być oznaczona przez programistę za pomocą rzutowania, np. int i = (int)2.3f;
Niejawna konwersja nie musi, np. float f = 2;
Może na początek kod implementujący podany w książce przykład: (głupie zwracane wartości, ale to chwilowo nieważne):
class ETS // EST == EarthTimeSpan
{
public static explicit operator short(ETS e) { return 0; }
}
class BTS // BTS == BliposTimeSpan
{
public static implicit operator BTS(double d) { return null; }
}
No i teraz po kolei:
a) myDecimal = bliposTimeSpan1;
Nie ma konwersji do decimala z BTS - jest odwrotna. Nie ma co więcej pisać, dalej:
b) myDecimal = (decimal) bliposTimeSpan1;
Dokładnie to co powyżej, nie ma żadnej konwersji.
c) myShort = (short) bliposTimeSpan1;
Tym bardziej nie ma do shorta, nudne te przykłady :>
d) myShort = earthTimeSpan1;
Ech, znowu nic nowego...
e) myShort = (short)earthTimeSpan;
Jest konwersja (jawna) do shorta zdefiniowana przez nas - static explicit operator short(ETS e)
- więc działa.
f) myDecimal = earthTimeSpan;
Ale nie ma niejawnej konwersji (więcej w następnym punkcie).
g) myDecimal = (decimal)earthTimeSpan;
O, coś ciekawszego.
Punkt 13.4.4 standardu, User Defined Explicit Conversions.
Jest dość długi, ale w podsumowaniu najciekawszych, z punktu widzenia przykładu, części:
- znajdywana jest
'najbardziej pasująca'
konwersja (dokładne zasady opisane)
- magia :>
S = typ źródłowy (tutaj ETS)
T = typ deocelowy (tutaj decimal)
SX = najbliższy typ z którego wykonywana jest konwersja (tutaj ETS) - musi być konwertowalny za pomocą standardowej konwersji z S
TX = najbliższy typ do którego jest konwertowany (tutaj **short**) - musi być konwertowany za pomocą standardowej konwersji do T
• Finally, apply the conversion:
o If S is not SX, then a standard explicit conversion from S to SX is performed. // S jest SX
o The most specific conversion operator is invoked to convert from SX to TX. // public static explicit operator short(ETS e)
o If TX is not T, then a standard explicit [patrz - notatka] conversion from TX to T is performed. // standardowa konwersja short -> decimal
Notka - konwersja short -> decimal jest implicit, ale wszystkie standardowe konwersje implicit są z automatu explicit:
13.3.2 Standard explicit conversions
The standard explicit conversions are all standard implicit conversions plus the subset of the explicit
conversions for which an opposite standard implicit conversion exists. [Note : In other words, if a standard
implicit conversion exists from a type A to a type B, then a standard explicit conversion exists from type A to
type B and from type B to type A. end note]
Wtedy mamy coś takiego jak:
myDecimal = jakiś_decimal
Co jest oczywiście poprawne.
Czyli w skrócie, po ludzku - wykonywana jest najbardziej pasująca konwersja, i typ wynikający z tej konwersji jest dodatkowo konwertowany do typu ostateczniego (ETS->short->decimal) za pomocą niejawnej, standardowej konwersji (13.1.2, implicit number conversions).
13.1.2 Implicit numeric conversions
The implicit numeric conversions are:
(...)
From short to int, long, float, double, or decimal.
(...)
h) bliposTimeSpan1 = earthTimeSpan1;
ETS nie ma niejawnej konwersji do żadnego (ok, oprócz System.Object) typu, to po prostu nie może działać.
i) bliposTimeSpan1 = (short)earthTimeSpan1;
ETS jest konwertowany jawnie do short-a (żadne cuda), i teraz mamy sytuację taką
bliposTimeSpan1 = jakis_short;
Tutaj konwersja idzie jak w g), zmienia się końcówka. Mamy tam:
BTS = jakiś_decimal
Którą ofc da się prosto wykonać.
j) bliposTimeSpan1 = (decimal)earthTimeSpan1;
Praktycznie to samo co g, tylko ostatnia konwersja to nie standardowa konwersja short->decimal, tylko static implicit operator BTS(decimal d)
k) earthTimeSpan1=bliposTimeSpan1;
l) earthTimeSpan1=(short) bliposTimeSpan1;
m) earthTimeSpan1= (decimal) bliposTimeSpan1;
BTS nie ma żadnej konwersji do niczego (oprócz object ofc), koniec zabawy.
Ok, to 'kompetentne'
odpowiedzi udzielone. Ale można do tego podejść 'luźniej'
, mniej formalnie...
Streszczenie wszystkich zasad:
- jeśli jest zdefiniowana w kodzie konwersja z typu A do B, wykonaj ją
- jeśli nie, znajdź najbliższą konwersję
pośrednią
, taką że A da się standardowo konwertować do AX, BX da się standardowo konwertować do B, a AX da się konwertować do BX (czyli ostatecznie A -> AX -> BX -> B).
- Czy konwersje dzielą się na jawne, jawne zdefiniowane przez użytkownika, niejawne, niejawne zdefiniowane przez użytkownika?
Nieścisłe trochę pytanie - standard wyróżnia konwersje 'użytkownika'
i 'standardowe'
, oraz dzieli je na 'jawne'
i 'niejawne'
. Konwersje jawne i niejawne są z reguły tak samo traktowane, aczkolwiek w niektórych przypadkach wymagane jest żeby konwersja była standardowa (jak wyżej).