Ludzie pragną czasami się rozstawać, żeby móc tęsknić, czekać i cieszyć się z powrotem.
..............................................127
Opcje kompilatora języka C# ................................................ 129
Istotne narzędzia środowiska .NET ...................................... 134
Skorowidz .............................................................................. 139
Opakowywanie i odpakowywanie
typów wartościowych
Aby można było wykonywać wspólne operacje — przeprowa-
dzane zarówno na typach referencyjnych, jak i wartościowych
— każdy typ wartościowy posiada odpowiadający mu ukryty
typ referencyjny. Zostaje on utworzony w przypadku przypisania
typu wartościowego do egzemplarza typu System.Object lub
do interfejsu. Proces ten zwany jest opakowywaniem (ang. boxing).
Typ wartościowy można rzutować do klasy object (wyjścio-
wej klasy bazowej dla wszystkich typów wartościowych i refe-
rencyjnych) lub do implementowanego przez niego interfejsu.
W zaprezentowanym tu przykładzie opakowujemy typ warto-
ściowy int w odpowiadający mu typ referencyjny, a następnie
odpakowujemy go:
class Test {
static void Main () {
int x = 9;
object o = x; // opakuj typ int
int y = (int)o; // odpakuj typ int
}
}
Podczas opakowywania typu wartościowego tworzony jest nowy
typ referencyjny, który przechowywać będzie kopię opakowy-
wanego typu. Operacja odpakowania powoduje przekopiowanie
wartości z typu referencyjnego z powrotem do typu wartościo-
wego. Wymaga ona jawnego rzutowania, podczas którego wyko-
nywane jest sprawdzenie, czy docelowy typ wartościowy jest
zgodny z typem zawartym w typie referencyjnym. W przypadku
niepomyślnego wyniku tego sprawdzenia zgłaszany jest wyjątek
InvalidCastException. Nie musimy się martwić o to, co stanie
się z opakowanymi obiektami, gdy przestaniemy z nich korzy-
Typy predefiniowane
3
stać — poradzi sobie z nimi za nas mechanizm odśmiecania pamięci.
Dobrym przykładem operacji opakowania i odpakowania jest za-
stosowanie klas kolekcji (ang. collection classes). W następującym
fragmencie kodu wykorzystujemy klasę Queue w połączeniu
z typami wartościowymi:
using System;
using System.Collections;
class Test {
static void Main () {
Queue q = new Queue ();
q.Enqueue (1); // opakuj wartość typu int
q.Enqueue (2); // opakuj wartość typu int
Console.WriteLine ((int)q.Dequeue()); // odpakuj
wartość typu int
Console.WriteLine ((int)q.Dequeue()); // odpakuj
wartość typu int
}
}
Typy predefiniowane
Wszystkie typy predefiniowane w języku C# są nazwami zastęp-
czymi typów występujących w przestrzeni nazw System. Na
przykład, pomiędzy następującymi dwoma instrukcjami istnieje
jedynie różnica składniowa:
int i = 5;
System.Int32 i = 5;
Typy całkowite
Typy całkowite oraz ich właściwości przedstawia zamieszczona
poniżej tabela.
4
C#. Leksykon kieszonkowy
W przypadku typów całkowitych bez znaku, o szerokości n bi-tów, możliwe wartości należą do zakresu od 0 do 2n–1. W przy-
padku typów całkowitych ze znakiem, o takiej samej szerokości
Typ w języku C#
Typ systemowy
Rozmiar
Ze znakiem
sbyte
System.SByte
1 bajt
Tak
short
System.Int16
2 bajty
Tak
int
System.Int32
4 bajty
Tak
long
System.Int64
8 bajtów
Tak
byte
System.Byte
1 bajt
Nie
ushort
System.UInt16
2 bajty
Nie
uint
System.UInt32
4 bajty
Nie
ulong
System.UInt64
8 bajtów
Nie
(n bitów), możliwe wartości mieszczą się w zakresie od –2n–1 do
2n–1–1. W literałach całkowitych stosować można notację dzie-
siętną lub szesnastkową:
int x = 5;
ulong y = 0x1234AF; // w przypadku liczb
szesnastkowych stosujemy przedrostek 0x
W przypadku, gdy dany literał całkowity jest poprawny dla kilku
możliwych typów całkowitych, typ domyślny wybierany jest
w następującej kolejności: int, uint, long oraz ulong. W celu
jawnego określenia wybranego typu można użyć następujących
przyrostków:
U
uint lub ulong
L
long lub ulong
UL
ulong
Typy predefiniowane
5
Konwersje całkowite
Niejawna konwersja pomiędzy typami całkowitymi jest dozwo-
lona w przypadku, gdy typ, na który chcemy konwertować,
zawiera wszystkie możliwe wartości typu konwertowanego.
W przeciwnym razie konieczna jest konwersja jawna. Możemy,
na przykład, niejawnie skonwertować typ int na typ long,
lecz typ int na typ short musimy już konwertować jawnie:
int x = 123456;
long y = x; // konwersja niejawna, nie ma utraty
informacji
short z = (short)x; // konwersja jawna, wartość x
zostaje "obcięta"
Typy zmiennoprzecinkowe
Typ w języku C#
Typ systemowy
Rozmiar
float
System.Single
4 bajty
double
System.Double
8 bajtów
Typ float może pomieścić wartości z zakresu od około ±1,5×10–45
do około ±3,4×1038, z dokładnością do siedmiu cyfr znaczących.
Typ double może pomieścić wartości z zakresu od około ±5,0×
10–324 do około ±1,7×10308, z dokładnością do 15 – 16 cyfr znaczących.
Typy zmiennoprzecinkowe mogą przechowywać wartości spe-
cjalnie +0, –0, +∞, –∞, NaN (ang. not a number — wartość nielicz-
bowa). Reprezentują one wyniki takich operacji matematycz-
nych jak dzielenie przez zero. Typy float oraz double stanowią
implementację specyfikacji typów formatu IEEE 754, obsługiwaną
przez prawie wszystkie procesory, a zdefiniowaną przez orga-
nizację IEEE w witrynie http://www.ieee.org.
6
C#. Leksykon kieszonkowy
W literałach zmiennoprzecinkowych stosować można notację dziesiętną lub wykładniczą. Literał typu float wymaga dołą-
czenia przyrostka f lub F. Do literału typu double można (lecz
nie jest to koniecznie) dodać przyrostek d lub D.
float x = 9.81f;
double y = 7E-02; // 0.07
Konwersje zmiennoprzecinkowe
Niejawna konwersja typu float na typ double nie powoduje
utraty informacji i jest dozwolona — lecz nigdy na odwrót. Dla
zapewnienia czytelności dozwolona jest również konwersja typów
int, uint i long na typ float oraz typu long na typ double:
int sila = 2;
int przesuniecie = 3;
float x = 9.53f * sila - przesuniecie;
Jeśli w przykładzie tym użyjemy większych wartości, może na-
stąpić utrata precyzji. Jednak możliwy zakres wartości nie jest okrojony, ponieważ najniższa i najwyższa wartość zarówno typu
float, jak i double, przekraczają najniższą i najwyższą wartość
typów int, uint czy long. Wszystkie pozostałe konwersje po-
między typami całkowitymi a zmiennoprzecinkowymi muszą
być jawne:
float x = 3.53f;
int przesuniecie = (int)x;
Typ dziesiętny (decimal)
Typ decimal może przechowywać wartości z zakresu od ±1,0×
10–28 do około ±7,9×1028, przy użyciu 28 – 29 cyfr znaczących.
Typ decimal zawiera 28 cyfr oraz położenie przecinka oddzie-
lającego części dziesiętne. W przeciwieństwie do wartości zmien-Typy predefiniowane
7