Руководство по программированию на 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#.

См. также