Poniższy artykuł pochodzi z serii Przygotowań do egzaminu 70-536.
Konwersja pozwala porównywać i kopiować wartości pomiędzy różnymi typami danych. Może być przeprowadzona w sposób jawny (ang. explicit conversion), bądź niejawny (ang. implicit conversion). C# zabrania niejawnej konwersji w przypadku, gdy może dojść do utraty dokładności. Pozwala natomiast, gdy typ docelowy może pomieścić wszystkie wartości z typu źródłowego, co nazywane jest konwersją rozszerzająca (ang. widening conversion). Przykładowo można dokonać konwersji z typu Int32, na Double, ponieważ Double może przechować każdą wartość typu Int32.
1: int i = 1;
2: double d = i; // Konwersja dozwolona
Uwaga: Nie możemy niejawnie wykonać konwersji, np. typu Int32 na Int16, czy Double na Int16.
Jeżeli zakres typu źródłowego przekracza ten z typu docelowego, musimy zastosować konwersję zawężającą (ang. narrowing conversion), która jednak może zwrócić nieprawidłowy wynik, jeżeli wartość źródłowa przekroczy zakres typu docelowego. Konwersja ta zwykle jest jawna.
1: double d = 1.0001;
2: int i = (int) d; // 1
Jeżeli nie użyjemy operatora rzutowania dostaniemy błąd:
Cannot implicitly convert type 'double' to 'int'. An explicit conversion exists (are you missing a cast?)
W przypadku jawnej konwersji napisu (typ string) do innego typu możemy wykorzystać metody type.Parse i type.TryParse. Pierwsza zgłasza wyjatęk w razie niepowodzenia, druga – zwraca wartość logiczną wskazującą, czy operacja się powiodła.
1: int j = 0;
2: try
3: {
4: j = int.Parse("123");
5: }
6: catch(FormatException)
7: {
8: j = 13;
9: }
10:
11: int k = 0;
12: if(int.TryParse("456", out k))
13: {
14: // Udało się
15: } else
16: {
17: // Parsowanie nie powiodło się
18: }
Jeżeli chcemy zamienić obiekt na string wywołujemy jego metodę ToString.
1: string s = 123.ToString(); // "123"
2: string u = new Program().ToString(); // "Boxing.Program"
Pakowanie i rozpakowywanie
Pakowanie (ang. boxing) i rozpakowywanie (ang. unboxing) pozwala na traktowanie typów wartościowych (skalarnych) jako pełnoprawnych obiektów. Pakowanie zamienia typ wartościowy do referencyjnego, rozpakowywanie odwrotnie - zamienia typ referencyjny do wartościowego.
1: // Boxing
2: int i = 123;
3: object o = (object) i;
4: // Unboxing
5: object p = 456;
6: int j = (int) p;
Omawiana technika powinna być unikana głównie dlatego, że wzrasta przez nią obciążenie (ang. overhead).
Struktury dziedziczą metodę ToString z System.Object. Często nadpisuje się tą metodę, aby uniknąć pakowania – typy wartościowe są pakowane podczas gdy metoda ToString odziedziczona z System.Object jest wywoływana. Nadpisanie metody pozwala tego uniknąć. Dodatkowo domyślnie metoda ToString zwraca nazwę typu, co jest zwykle mało przydatne. Nadpisując metodę możemy zmienić to zachowanie.
Konwertowanie naszych własnych typów
W zależności od konwersji jaką chcemy podjąć możemy skorzystać z każdego z kilku typów konwersji:
Zdefiniowanie operatorów konwersji pozwala przypisywać wartości z typu skalarnego do stworzonego przez nas. W tym celu wykorzystujemy słowa kluczowe implicit i explicit.
1: struct TypeA
2: {
3: public int Value;
4:
5: // Niejawna konwersja
6: public static implicit operator TypeA(int arg)
7: {
8: TypeA res = new TypeA();
9: res.Value = arg;
10: return res;
11: }
12:
13: // Konwersja jawna
14: public static explicit operator int(TypeA arg)
15: {
16: return arg.Value;
17: }
18:
19: // Konwersja do typu String
20: public override string ToString()
21: {
22: return Value.ToString();
23: }
24: }
Wywołanie:
1: TypeA a;
2: int i;
3: a = 13;
4: i = (int) a;
5: // Wywołane zostaną metody ToString
6: Console.WriteLine("a = {0}, i = {1}", a, i); // 13, 13
Aby zaimplementować interfejs System.IConvertible należy go dodać do definicji typu:
1: class TypeB : System.IConvertible
2: {
3: }
Następnie przy pomocy Visual Studio generujemy deklaracje dla wszystkich wymaganych metod (np. GetTypeCode, ChangeType, ToType, ToBoolean, ToChar). W metodach, które nie będą nam potrzebne pozostawiamy kod:
1: throw new System.NotImplementedException();
Po zaimplementowaniu interfejsu IConvertible możemy korzystać z klasy System.Convert:
1: TypeB a;
2: bool b;
3: a = 44;
4: b = Convert.ToBoolean(a);
5: Console.WriteLine("a = {0}, b = {1}", a, b); // 44, True
Kolejny artykuł z serii to 70-536: Working with the File System