Руководство по программированию на C#. Приведение и преобразование типов
Так как C# статически типируется во время компиляции, после объявления переменной его нельзя объявить еще раз или назначить значение другого типа, если этот тип неявно преобразуется в тип переменной. Например, string
невозможно неявно преобразовать в int
. Таким образом, после объявления i
как не int
удается назначить строку Hello, как показано в следующем коде:
int i;
// error CS0029: can't implicitly convert type 'string' to 'int'
i = "Hello";
Тем не менее иногда может потребоваться скопировать значение в переменную или параметр метода другого типа. Например, может потребоваться передать целочисленную переменную в метод, параметр которого имеет тип double
. Или может понадобиться присвоить переменную класса переменной типа интерфейса. Такого рода операции называются преобразованиями типа. В C# можно выполнять следующие виды преобразований.
Неявные преобразования: специальный синтаксис не требуется, так как преобразование всегда выполняется успешно, и данные не теряются. Примеры включают преобразования из меньших в большие целочисленные типы и преобразования из производных классов в базовые классы.
Явные преобразования (приведения): для явных преобразований требуется выражение приведения. Приведение требуется, если в ходе преобразования данные могут быть утрачены или преобразование может завершиться сбоем по другим причинам. Типичными примерами являются числовое преобразование в тип с меньшей точностью или меньшим диапазоном и преобразование экземпляра базового класса в производный класс.
Определяемые пользователем преобразования: определяемые пользователем преобразования используют специальные методы, которые можно определить, чтобы включить явные и неявные преобразования между пользовательскими типами, у которых нет связи на основе базового класса. Дополнительные сведения см. в разделе Операторы пользовательского преобразования.
Преобразования с использованием вспомогательных классов. Чтобы выполнить преобразование между несовместимыми типами, например целыми числами и объектами System.DateTime или шестнадцатеричными строками и массивами байтов, можно использовать классы System.BitConverter и System.Convert, а также методы
Parse
встроенных числовых типов, такие как Int32.Parse. Дополнительные сведения см. в руководствах по преобразованию массива байтов в значение типа int, преобразованию строки в число и преобразованию из шестнадцатеричных строк в числовые типы.
Неявные преобразования
Для встроенных числовых типов неявное преобразование можно выполнить, если сохраняемое значение может уместиться в переменной без усечения или округления. При использовании целочисленных типов это означает, что диапазон исходного типа является надлежащим подмножеством диапазона для целевого типа. Например, переменная типа long (64-разрядное целое число) может хранить любое значение, которое может хранить переменная int (32-разрядное целое число). В следующем примере компилятор неявно преобразует значение num
справа в тип long
перед назначением bigNum
.
// Implicit conversion. A long can
// hold any value an int can hold, and more!
int num = 2147483647;
long bigNum = num;
Полный список всех неявных числовых преобразований см. в разделе Таблица неявных числовых преобразований в статье Встроенные числовые преобразования.
Для ссылочных типов неявное преобразование всегда предусмотрено из класса в любой из его прямых или косвенных базовых классов или интерфейсов. Никакой специальный синтаксис не требуется, поскольку производный класс всегда содержит все члены базового класса.
Derived d = new Derived();
// Always OK.
Base b = d;
Явные преобразования
Однако если преобразование невозможно сделать без риска потери информации, компилятору требуется выполнить явное преобразование, которое называется приведением. Приведение — это способ явного информирования компилятора о том, что вы планируете выполнить преобразование и что вы знаете, что потеря данных может произойти, или приведение может завершиться ошибкой во время выполнения. Чтобы выполнить приведение, укажите тип, к которому выполняется приведение в круглые скобки перед преобразуемой значением или переменной. Следующая программа приводит двойник к int. Программа не будет компилироваться без приведения.
class Test
{
static void Main()
{
double x = 1234.7;
int a;
// Cast double to int.
a = (int)x;
System.Console.WriteLine(a);
}
}
// Output: 1234
Полный список всех поддерживаемых явных числовых преобразований см. в разделе Таблица явных числовых преобразований в статье Встроенные числовые преобразования.
Для ссылочных типов явное приведение является обязательным, если необходимо преобразовать базовый тип в производный тип:
// 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;
Операция приведения между ссылочными типами не изменяет тип времени выполнения базового объекта; он изменяет только тип значения, используемого в качестве ссылки на этот объект. Дополнительные сведения см. в разделе Полиморфизм.
Исключения преобразования типов во время выполнения
В некоторых преобразованиях ссылочного типа компилятор не может определить, является ли приведение допустимым. Можно выполнить операцию приведения, которая правильно компилируется во время выполнения. Как показано в следующем примере, приведение типа, завершающееся сбоем во время выполнения, приводит 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;
}
}
Метод Test
имеет параметр Animal
, поэтому явное приведение a
аргумента к Reptile
формирует опасное допущение. Это безопаснее, чтобы не делать предположения, а вместо проверка тип. C# предоставляет оператор is, чтобы можно было проверить совместимость перед фактическим выполнением приведения. Дополнительные сведения см. в статье Практическое руководство. Безопасное приведение с помощью сопоставления шаблонов, а также операторов is и as.
Спецификация языка C#
Дополнительные сведения см. в разделе Преобразованияспецификация языка C#.