Konwersje rzutowania i typów (Przewodnik programowania w języku C#)
Ponieważ język C# jest statycznie typizowane w czasie kompilacji, po zadeklarowaniu zmiennej nie można go ponownie zadeklarować ani przypisać wartości innego typu, chyba że ten typ jest niejawnie konwertowany na typ zmiennej. Na przykład nie można niejawnie przekonwertować elementu string
na int
. W związku z tym po zadeklarowaniu i
jako int
elementu nie można przypisać do niego ciągu "Hello", jak pokazano w poniższym kodzie:
int i;
// error CS0029: can't implicitly convert type 'string' to 'int'
i = "Hello";
Czasami jednak może być konieczne skopiowanie wartości do zmiennej lub parametru metody innego typu. Na przykład może istnieć zmienna całkowita, która musi zostać przekazana do metody, której parametr jest wpisany jako double
. Może też być konieczne przypisanie zmiennej klasy do zmiennej typu interfejsu. Tego rodzaju operacje są nazywane konwersjami typów. W języku C#można wykonać następujące rodzaje konwersji:
Konwersje niejawne: nie jest wymagana żadna specjalna składnia, ponieważ konwersja zawsze kończy się powodzeniem i żadne dane nie zostaną utracone. Przykłady obejmują konwersje z mniejszych do większych typów całkowitych oraz konwersje z klas pochodnych na klasy bazowe.
Konwersje jawne (rzuty): konwersje jawne wymagają wyrażenia rzutowego. Rzutowanie jest wymagane, gdy informacje mogą zostać utracone w konwersji lub gdy konwersja może się nie powieść z innych powodów. Typowe przykłady obejmują konwersję liczbową na typ, który ma mniejszą precyzję lub mniejszy zakres, oraz konwersję wystąpienia klasy bazowej na klasę pochodną.
Konwersje zdefiniowane przez użytkownika: konwersje zdefiniowane przez użytkownika używają specjalnych metod, które można zdefiniować w celu włączenia jawnych i niejawnych konwersji między typami niestandardowymi, które nie mają relacji klasy bazowej pochodnej. Aby uzyskać więcej informacji, zobacz Operatory konwersji zdefiniowane przez użytkownika.
Konwersje z klasami pomocnika: aby przekonwertować między typami niezgodnymi, takimi jak liczby całkowite i System.DateTime obiekty, lub ciągi szesnastkowe i tablice bajtowe, można użyć System.BitConverter klasy, System.Convert klasy i
Parse
metod wbudowanych typów liczbowych, takich jak Int32.Parse. Aby uzyskać więcej informacji, zobacz How to convert a byte array to an int ( Jak przekonwertować ciąg na liczbę) oraz How to convert between hexadecimal strings and numberic types (Jak konwertować ciągi szesnastkowe i typy liczbowe).
Niejawne konwersje
W przypadku wbudowanych typów liczbowych można dokonać niejawnej konwersji, gdy wartość, która ma być przechowywana, może mieścić się w zmiennej bez obcinania lub zaokrąglania. W przypadku typów całkowitych oznacza to, że zakres typu źródłowego jest odpowiednim podzbiorem zakresu dla typu docelowego. Na przykład zmienna typu długa (64-bitowa liczba całkowita) może przechowywać dowolną wartość, którą może przechowywać liczba całkowita (32-bitowa liczba całkowita). W poniższym przykładzie kompilator niejawnie konwertuje wartość po num
prawej stronie na typ long
przed przypisaniem go do bigNum
elementu .
// Implicit conversion. A long can
// hold any value an int can hold, and more!
int num = 2147483647;
long bigNum = num;
Aby uzyskać pełną listę wszystkich niejawnych konwersji liczbowych, zobacz sekcję Niejawne konwersje liczbowe w artykule Wbudowane konwersje liczbowe.
W przypadku typów referencyjnych konwersja niejawna zawsze istnieje z klasy do dowolnej z jej bezpośrednich lub pośrednich klas bazowych lub interfejsów. Nie jest wymagana żadna specjalna składnia, ponieważ klasa pochodna zawsze zawiera wszystkie elementy członkowskie klasy bazowej.
Derived d = new Derived();
// Always OK.
Base b = d;
Konwersje jawne
Jeśli jednak nie można dokonać konwersji bez ryzyka utraty informacji, kompilator wymaga wykonania jawnej konwersji, która jest nazywana rzutacją. Rzutowanie to sposób jawnego informowania kompilatora, że zamierzasz dokonać konwersji i że wiadomo, że może wystąpić utrata danych lub rzutowanie może zakończyć się niepowodzeniem w czasie wykonywania. Aby wykonać rzutowanie, określ typ rzutowany w nawiasach przed wartością lub zmienną do przekonwertowania. Poniższy program rzutuje dwukrotnie na int. Program nie zostanie skompilowany bez rzutowania.
class Test
{
static void Main()
{
double x = 1234.7;
int a;
// Cast double to int.
a = (int)x;
System.Console.WriteLine(a);
}
}
// Output: 1234
Aby uzyskać pełną listę obsługiwanych jawnych konwersji liczbowych, zobacz sekcję Jawne konwersje liczbowe w artykule Wbudowane konwersje liczbowe.
W przypadku typów referencyjnych wymagana jest jawna rzutowanie, jeśli musisz przekonwertować typ podstawowy na typ pochodny:
// Create a new derived type.
Giraffe g = new Giraffe();
// Implicit conversion to base type is safe.
Animal a = g;
// Explicit conversion is required to cast back
// to derived type. Note: This will compile but will
// throw an exception at run time if the right-side
// object is not in fact a Giraffe.
Giraffe g2 = (Giraffe)a;
Operacja rzutowania między typami odwołań nie zmienia typu czasu wykonywania obiektu bazowego; zmienia tylko typ wartości, która jest używana jako odwołanie do tego obiektu. Aby uzyskać więcej informacji, zobacz Polymorphism (Polimorfizm).
Wyjątki konwersji typów w czasie wykonywania
W niektórych konwersjach typów odwołań kompilator nie może określić, czy rzutowanie jest prawidłowe. Istnieje możliwość wykonania operacji rzutowania, która kompiluje się poprawnie, aby zakończyć się niepowodzeniem w czasie wykonywania. Jak pokazano w poniższym przykładzie, rzutowanie typu, które kończy się niepowodzeniem w czasie wykonywania, powoduje zgłoszenie elementu InvalidCastException .
class Animal
{
public void Eat() => System.Console.WriteLine("Eating.");
public override string ToString() => "I am an animal.";
}
class Reptile : Animal { }
class Mammal : Animal { }
class UnSafeCast
{
static void Main()
{
Test(new Mammal());
// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
static void Test(Animal a)
{
// System.InvalidCastException at run time
// Unable to cast object of type 'Mammal' to type 'Reptile'
Reptile r = (Reptile)a;
}
}
Metoda Test
ma Animal
parametr, w związku z czym jawnie rzutuje argument a
na Reptile
niebezpieczne założenie. Bezpieczniej jest nie podjąć założeń, ale raczej sprawdzić typ. Język C# udostępnia operator is , aby umożliwić testowanie pod kątem zgodności przed rzeczywistym wykonaniem rzutowania. Aby uzyskać więcej informacji, zobacz Jak bezpiecznie rzutować przy użyciu dopasowywania wzorca i operatorów as i is.
specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz sekcję Konwersje specyfikacji języka C#.