Поделиться через


Преобразования в Visual Basic

Преобразование — это процесс изменения значения с одного типа на другой. Например, значение типа Integer можно преобразовать в значение типа, или значение типа DerivedDoubleможно преобразовать в значение типаBase, предполагая, что Base и Derived классы и Derived наследуются от Baseнего. Преобразования могут не требовать изменения самого значения (например, в последнем примере), или они могут потребовать существенных изменений в представлении значений (как в предыдущем примере).

Преобразования могут быть расширенными или сужающими. Расширение преобразования — это преобразование из типа в другой тип, домен значений которого по крайней мере больше, если не больше, чем домен значений исходного типа. Расширение преобразований никогда не должно завершаться ошибкой. Сужающее преобразование — это преобразование из типа в другой тип, домен значений которого меньше домена значения исходного типа или достаточно не связан с тем, что при преобразовании из него необходимо выполнить дополнительную осторожность (например, при преобразовании из Integer ).String Сужающие преобразования, которые могут привести к потере информации, могут завершиться ошибкой.

Преобразование удостоверений (т. е. преобразование из типа в сам по себе) и преобразование значений по умолчанию (т. е. преобразование из Nothing) определяется для всех типов.

Неявные и явные преобразования

Преобразования могут быть неявными или явными. Неявные преобразования происходят без специального синтаксиса. Ниже приведен пример неявного преобразования Integer значения Long в значение:

Module Test
    Sub Main()
        Dim intValue As Integer = 123
        Dim longValue As Long = intValue

        Console.WriteLine(intValue & " = " & longValue)
    End Sub
End Module

С другой стороны, явные преобразования требуют операторов приведения. Попытка выполнить явное преобразование значения без оператора приведения приводит к ошибке во время компиляции. В следующем примере используется явное преобразование для преобразования Long значения в Integer значение.

Module Test
    Sub Main()
        Dim longValue As Long = 134
        Dim intValue As Integer = CInt(longValue)

        Console.WriteLine(longValue & " = " & intValue)
    End Sub
End Module

Набор неявных преобразований зависит от среды компиляции и инструкции Option Strict . Если используется строгая семантика, могут возникать неявно только расширенные преобразования. Если используется неявная семантика, все расширения и сужения преобразований (другими словами, все преобразования) могут происходить неявно.

Логические преобразования

Хотя Boolean и не является числовым типом, он имеет сужающие преобразования в числовые типы и из них, как если бы это был перечислимый тип. Литерал преобразуется в литерал True255 для Byte, 65535 for UShort, 4294967295 for UInteger18446744073709551615 , for ULong, и в выражение -1 для SByte, , LongShortDecimalIntegerSingleи .Double Литерал преобразуется в литерал False0. Нулевое числовое значение преобразуется в литерал False. Все остальные числовые значения преобразуются в литерал True.

Существует сужающее преобразование из логического в string, преобразующееся в любой System.Boolean.TrueString или System.Boolean.FalseString. Также имеется сужение преобразования из StringBoolean: если строка была равной TrueString или FalseString (в текущем языке и региональных параметрах, без учета регистра), то она использует соответствующее значение; в противном случае она пытается проанализировать строку как числовый тип (в шестнадцатеричном или восьмеричном, если это возможно, в противном случае как плавающее значение) и использует приведенные выше правила; в противном случае он вызывает System.InvalidCastException.

Числовые преобразования

Числовые преобразования существуют между типамиByte, ShortUIntegerIntegerUShortSByteLongDecimalULongSingle и Doubleвсеми перечисленными типами. При преобразовании перечисляемые типы обрабатываются так, как если бы они были их базовыми типами. При преобразовании в перечислимый тип исходное значение не требуется для соответствия набору значений, определенных в перечисленном типе. Рассмотрим пример.

Enum Values
    One
    Two
    Three
End Enum

Module Test
    Sub Main()
        Dim x As Integer = 5

        ' OK, even though there is no enumerated value for 5.
        Dim y As Values = CType(x, Values)
    End Sub
End Module

Числовые преобразования обрабатываются во время выполнения следующим образом:

  • Для преобразования из числового типа в более широкий числовой тип значение просто преобразуется в более широкий тип. Преобразования из , Integer, или ULongLongв UIntegerили DoubleSingleDecimal округляются до ближайшего Single или Double значения. Хотя это преобразование может привести к потере точности, она никогда не приведет к потере величины.

  • Для преобразования из целочисленного типа в другой целочисленный или из , Doubleлибо Decimal в Singleцелочисленный тип, результат зависит от того, включена ли проверка целочисленного переполнения:

    Если выполняется проверка целочисленного переполнения:

    • Если источник является целочисленным типом, преобразование завершается успешно, если исходный аргумент находится в диапазоне целевого типа. Преобразование вызывает исключение, если исходный System.OverflowException аргумент находится за пределами диапазона целевого типа.

    • Если источник имеет Singleзначение , Doubleили Decimalисходное значение округляется вверх или вниз до ближайшего целочисленного значения, и это целочисленное значение становится результатом преобразования. Если исходное значение равно близко к двум целочисленным значениям, значение округляется до значения, которое имеет четное число в наименьшей позиции цифры. Если результирующее целочисленное значение выходит за пределы диапазона целевого типа, System.OverflowException создается исключение.

    Если целочисленный переполнение не проверяется:

    • Если источник является целочисленным типом, преобразование всегда выполняется успешно и просто состоит из отмены наиболее значимых битов исходного значения.

    • Если источник имеет Singleзначение , Doubleили Decimalпреобразование всегда выполняется успешно и просто состоит из округления исходного значения в сторону ближайшего целочисленного значения. Если исходное значение равно близко к двум целочисленным значениям, значение всегда округляется до значения, которое имеет четное число в наименьшей позиции цифры.

  • Для преобразования из DoubleSingleв , Double значение округляется до ближайшего Single значения. Double Если значение слишком мало для представления в видеSingle, результат становится положительным нулем или отрицательным нулем. Double Если значение слишком большое, чтобы представить в видеSingle, результат становится положительным бесконечностью или отрицательным бесконечностью. Double Если значение равноNaN, результат также NaN.

  • Для преобразования из Single или DoubleDecimalв , исходное значение преобразуется в Decimal представление и округляется до ближайшего числа после 28-го десятичного разряда при необходимости. Если исходное значение слишком мало для представления в виде Decimal, результат становится нулевым. Если исходное значение равно NaN, бесконечности или слишком большому для представления в виде Decimal, System.OverflowException создается исключение.

  • Для преобразования из DoubleSingleв , Double значение округляется до ближайшего Single значения. Double Если значение слишком мало для представления в видеSingle, результат становится положительным нулем или отрицательным нулем. Double Если значение слишком большое, чтобы представить в видеSingle, результат становится положительным бесконечностью или отрицательным бесконечностью. Double Если значение равноNaN, результат также NaN.

Ссылочные преобразования

Ссылочные типы могут быть преобразованы в базовый тип, и наоборот. Преобразования из базового типа в более производный тип выполняются только во время выполнения, если преобразуемое значение является значением NULL, производным типом или более производным типом.

Типы классов и интерфейсов можно привести к любому типу интерфейса и из любого типа интерфейса. Преобразования между типом и типом интерфейса выполняются только во время выполнения, если фактические типы, связанные с наследованием или реализацией. Так как тип интерфейса всегда будет содержать экземпляр типа, наследуемого от Object, тип интерфейса также всегда может быть приведение к и из Object.

Примечание. Это не ошибка преобразования NotInheritable классов в интерфейсы и из интерфейсов, которые он не реализует, так как классы, представляющие классы COM, могут иметь реализации интерфейса, которые не известны до времени выполнения.

Если преобразование ссылок завершается ошибкой System.InvalidCastException во время выполнения, создается исключение.

Ссылки на преобразования дисперсии

Универсальные интерфейсы или делегаты могут иметь параметры типа вариантов, разрешающие преобразование между совместимыми вариантами типа. Таким образом, во время выполнения преобразование из типа класса или типа интерфейса в тип интерфейса, совместимый с типом интерфейса, который он наследует или реализует, будет выполнен успешно. Аналогичным образом типы делегатов можно привести к типам делегатов, совместимым с вариантом, и из них. Например, тип делегата

Delegate Function F(Of In A, Out R)(a As A) As R

разрешить преобразование из F(Of Object, Integer)F(Of String, Integer). То есть делегат, F который принимается Object , может быть безопасно использован в качестве делегата F , который принимает String. При вызове делегата целевой метод ожидает объекта, а строка — объект.

Универсальный делегат или тип S(Of S1,...,Sn) интерфейса, как правило, совместим с универсальным интерфейсом или типом T(Of T1,...,Tn) делегата, если:

  • S и T оба создаются из одного универсального типа U(Of U1,...,Un).

  • Для каждого параметра Uxтипа:

    • Если параметр типа был объявлен без дисперсии, то Sx он Tx должен быть одинаковым.

    • Если был объявлен In параметр типа, то должно быть расширение удостоверения, по умолчанию, ссылки, массива или преобразования параметров типа в SxTx.

    • Если был объявлен Out параметр типа, то должно быть расширение удостоверения, по умолчанию, ссылки, массива или преобразования параметров типа в TxSx.

При преобразовании из класса в универсальный интерфейс с параметрами типа вариантов, если класс реализует несколько совместимых вариантов интерфейс преобразования неоднозначно, если преобразование не является вариантным. Рассмотрим пример.

Class Base
End Class

Class Derived1
    Inherits Base
End Class

Class Derived2
    Inherits Base
End Class

Class OneAndTwo
    Implements IEnumerable(Of Derived1)
    Implements IEnumerable(Of Derived2)
End Class

Class BaseAndOneAndTwo
    Implements IEnumerable(Of Base)
    Implements IEnumerable(Of Derived1)
    Implements IEnumerable(Of Derived2)
End Class

Module Test
    Sub Main()
        ' Error: conversion is ambiguous
        Dim x As IEnumerable(Of Base) = New OneAndTwo()

        ' OK, will pick up the direct implementation of IEnumerable(Of Base)
        Dim y as IEnumerable(Of Base) = New BaseAndOneAndTwo()
    End Sub
End Module

Преобразование анонимных делегатов

Если выражение, классифицированное как лямбда-метод, классифицируется как значение в контексте, в котором нет целевого типа (например, Dim x = Function(a As Integer, b As Integer) a + bили где целевой тип не является типом делегата, тип результирующего выражения является анонимным типом делегата, эквивалентным сигнатуре лямбда-метода. Этот анонимный тип делегата имеет преобразование в любой совместимый тип делегата: совместимый тип делегата — это любой тип делегата, который можно создать с помощью выражения создания делегата с методом анонимного типа Invoke делегата в качестве параметра. Рассмотрим пример.

' Anonymous delegate type similar to Func(Of Object, Object, Object)
Dim x = Function(x, y) x + y

' OK because delegate type is compatible
Dim y As Func(Of Integer, Integer, Integer) = x

Обратите внимание, что типы System.Delegate и System.MulticastDelegate не считаются типами делегатов (даже если от них наследуются все типы делегатов). Кроме того, обратите внимание, что преобразование из анонимного типа делегата в совместимый тип делегата не является ссылочным преобразованием.

Преобразования массивов

Помимо преобразований, определенных на массивах, в силу того, что они являются ссылочными типами, для массивов существуют несколько специальных преобразований.

Для всех двух типов A и B, если они являются ссылочными типами или параметрами типа, не известными как типы значений, и если A имеет ссылку, массив или преобразование параметров Bтипа в, преобразование существует из массива типов A в массив типов B с одинаковым рангом. Эта связь называется ковариантностью массива. В частности, ковариация массива означает, что элемент массива, тип B элемента которого на самом деле может быть элементом массива, тип элемента которого имеет Aтип элемента, при условии, что A они B являются ссылочными типами и B имеют преобразование ссылок или преобразование массива в A. В следующем примере второй вызов F вызывает исключение, так как фактический тип b элемента имеет значение String, а не ObjectSystem.ArrayTypeMismatchException :

Module Test
    Sub F(ByRef x As Object)
    End Sub

    Sub Main()
        Dim a(10) As Object
        Dim b() As Object = New String(10) {}
        F(a(0)) ' OK.
        F(b(1)) ' Not allowed: System.ArrayTypeMismatchException.
   End Sub
End Module

Из-за ковариации массива назначения для элементов массивов ссылочных типов включают проверку времени выполнения, которая гарантирует, что значение, назначенное элементу массива, фактически является допустимым типом.

Module Test
    Sub Fill(array() As Object, index As Integer, count As Integer, _
            value As Object)
        Dim i As Integer

        For i = index To (index + count) - 1
            array(i) = value
        Next i
    End Sub

    Sub Main()
        Dim strings(100) As String

        Fill(strings, 0, 101, "Undefined")
        Fill(strings, 0, 10, Nothing)
        Fill(strings, 91, 10, 0)
    End Sub
End Module

В этом примере назначение в методе Fill неявно включает проверку времени выполнения, которая гарантирует, что объект, на который ссылается переменнаяvalue, либо Nothing экземпляр типа, совместимого с фактическим типом массиваarray.array(i) В методе первые два вызова метода MainFill успешно, но третий вызов приводит System.ArrayTypeMismatchException к возникновению исключения при выполнении первого назначенияarray(i). Исключение возникает, так как Integer невозможно хранить в массиве String .

Если один из типов элементов массива является параметром типа, тип которого оказывается типом значения во время выполнения, System.InvalidCastException создается исключение. Рассмотрим пример.

Module Test
    Sub F(Of T As U, U)(x() As T)
        Dim y() As U = x
    End Sub

    Sub Main()
        ' F will throw an exception because Integer() cannot be
        ' converted to Object()
        F(New Integer() { 1, 2, 3 })
    End Sub
End Module

Преобразования также существуют между массивом перечисленного типа и массивом базового типа перечисленного типа или массивом другого перечисленного типа с тем же базовым типом, если массивы имеют одинаковый ранг.

Enum Color As Byte
    Red
    Green
    Blue
End Enum

Module Test
    Sub Main()
        Dim a(10) As Color
        Dim b() As Integer
        Dim c() As Byte

        b = a    ' Error: Integer is not the underlying type of Color
        c = a    ' OK
        a = c    ' OK
    End Sub
End Module

В этом примере массив преобразуется в массив Color базового типа и из массиваByte. Color Однако преобразование в массив Integerбудет ошибкой, так как Integer не является базовым типом Color.

Массив типа A() ранг-1 также имеет преобразование массива в типы IList(Of B)интерфейса коллекции , IReadOnlyList(Of B)IReadOnlyCollection(Of B)ICollection(Of B)и IEnumerable(Of B) найдено в System.Collections.Generic, если одно из следующих значений имеет значение true:

  • A и B являются ссылочными типами или параметрами типа, которые не известны как типы значений; и A имеет расширение ссылки, преобразование Bмассива или типа в ; или
  • A и B являются перечисленными типами одного и того же базового типа; или
  • один из A и B является перечислимым типом, а другой — базовым типом.

Любой массив типа A с любым рангом также имеет преобразование массива в типы IListинтерфейсов, отличных от универсальных коллекций, ICollection и IEnumerable найден в System.Collections.

Можно выполнять итерацию по результирующий интерфейс с помощью For Eachили путем вызова GetEnumerator методов напрямую. В случае массивов ранга-1 преобразованы универсальные или не универсальные формы IList или ICollectionтакже можно получить элементы по индексу. В случае массивов ранга-1, преобразованных в универсальные или не универсальные формы IList, также можно задать элементы по индексу, при условии того же массива ковариации массива среды выполнения, как описано выше. Поведение всех других методов интерфейса не определено спецификацией языка VB; это до базовой среды выполнения.

Преобразования типов значений

Значение типа значения можно преобразовать в один из базовых ссылочных типов или тип интерфейса, который он реализует через процесс, называемый боксом. Если задано значение типа значения, значение копируется из расположения, в котором он находится в куче .NET Framework. Затем возвращается ссылка на это расположение в куче и может храниться в переменной ссылочного типа. Эта ссылка также называется прямоугольникой экземпляром типа значения. Прямоугольный экземпляр имеет ту же семантику, что и ссылочный тип, а не тип значения.

Типы значений boxed можно преобразовать обратно в исходный тип значения с помощью процесса, называемого распаковкой. При отмене поля типа значения значение копируется из кучи в расположение переменной. С этого момента он ведет себя так, как если бы он был типом значения. При распаковки типа значения значение должно быть значением NULL или экземпляром типа значения. System.InvalidCastException В противном случае создается исключение. Если значение является экземпляром перечисленного типа, это значение также может быть распаковано в базовый тип перечисленного типа или другой перечисленный тип, имеющий тот же базовый тип. Значение NULL обрабатывается как если бы это был литерал Nothing.

Для поддержки типов значений, допускающих значение NULL, тип значения System.Nullable(Of T) обрабатывается специально при выполнении бокса и распаковки. Поле значения типа Nullable(Of T) приводит к прямоугольнику типа T , если свойство значения HasValue равно True или значение Nothing , если свойство значения HasValue имеет Falseзначение. Распаковка значения типа TNullable(Of T) для получения результата в экземпляре Nullable(Of T) , свойство которого Value является полем и свойством которого HasValue является True. Nothing Значение может быть отключено Nullable(Of T) для любого T и приводит к значению, свойству которого HasValue являетсяFalse. Так как типы полей работают как ссылочные типы, можно создать несколько ссылок на одно и то же значение. Для примитивных типов и перечисленных типов это не имеет значения, так как экземпляры этих типов неизменяемы. То есть невозможно изменить прямоугольный экземпляр этих типов, поэтому невозможно наблюдать за тем, что существует несколько ссылок на одно и то же значение.

Структуры, с другой стороны, могут быть изменяемыми, если переменные экземпляра доступны или если его методы или свойства изменяют переменные экземпляра. Если для изменения структуры используется одна ссылка на боксную структуру, все ссылки на боксную структуру увидят изменения. Так как этот результат может быть непредвиденным, если тип значения, скопированное Object из одного расположения в другое поле, типы значений автоматически будут клонированы в кучу, а не просто скопированы их ссылки. Рассмотрим пример.

Class Class1
    Public Value As Integer = 0
End Class

Structure Struct1
    Public Value As Integer
End Structure

Module Test
    Sub Main()
        Dim val1 As Object = New Struct1()
        Dim val2 As Object = val1

        val2.Value = 123

        Dim ref1 As Object = New Class1()
        Dim ref2 As Object = ref1

        ref2.Value = 123

        Console.WriteLine("Values: " & val1.Value & ", " & val2.Value)
        Console.WriteLine("Refs: " & ref1.Value & ", " & ref2.Value)
    End Sub
End Module

Выходные данные программы:

Values: 0, 123
Refs: 123, 123

Назначение для поля локальной переменной не влияет на поле локальной переменной val2val1, так как при назначении val2поля Struct1 копия значения была сделана. В отличие от этого, назначение ref2.Value = 123 влияет на объект, который ref2ref1 и ссылается.

Примечание. Копирование структуры не выполняется для прямоугольных структур, типизированных, так как System.ValueType невозможно поздно выполнить привязку.System.ValueType

Существует одно исключение из правила, в которое будут скопированы типы значений, которые будут скопированы при назначении. Если ссылка на тип поля хранится в другом типе, внутренняя ссылка не будет скопирована. Рассмотрим пример.

Structure Struct1
    Public Value As Object
End Structure

Module Test
    Sub Main()
        Dim val1 As Struct1
        Dim val2 As Struct1

        val1.Value = New Struct1()
        val1.Value.Value = 10

        val2 = val1
        val2.Value.Value = 123
        Console.WriteLine("Values: " & val1.Value.Value & ", " & _
            val2.Value.Value)
    End Sub
End Module

Выходные данные программы:

Values: 123, 123

Это связано с тем, что внутреннее поле не копируется при копировании значения. Таким образом, оба val1.Value и val2.Value имеют ссылку на один и тот же тип поля значения.

Примечание. Тот факт, что внутренние типы значений не копируются, является ограничением системы типов .NET, чтобы убедиться, что все внутренние типы значений были скопированы всякий раз, когда было скопировано значение типа Object , будет запрещено дорого.

Как описано ранее, типы значений с полями могут быть распаковываются только в исходный тип. Тем не менее примитивные типы обрабатываются специально при типизированном виде Object. Их можно преобразовать в любой другой примитивный тип, в который они имеют преобразование. Рассмотрим пример.

Module Test
    Sub Main()
        Dim o As Object = 5
        Dim b As Byte = CByte(o)  ' Legal
        Console.WriteLine(b) ' Prints 5
    End Sub
End Module

Как правило, прямоугольное Integer значение 5 не может быть распаковлено в Byte переменную. Тем не менее, поскольку Integer и Byte являются примитивными типами и имеют преобразование, преобразование допускается.

Важно отметить, что преобразование типа значения в интерфейс отличается от универсального аргумента, ограниченного интерфейсом. При доступе к членам интерфейса в параметре ограниченного типа (или вызове методов) Objectбокс не происходит так, как это происходит при преобразовании типа значения в интерфейс и доступ к члену интерфейса. Например, предположим, что интерфейс ICounter содержит метод Increment , который можно использовать для изменения значения. Если ICounter используется в качестве ограничения, реализация Increment метода вызывается со ссылкой на вызываемую переменную Increment , а не боксированную копию:

Interface ICounter
    Sub Increment()
    ReadOnly Property Value() As Integer
End Interface

Structure Counter
    Implements ICounter

    Dim _value As Integer

    Property Value() As Integer Implements ICounter.Value
        Get
            Return _value
        End Get
    End Property

    Sub Increment() Implements ICounter.Increment
       value += 1
    End Sub
End Structure

Module Test
      Sub Test(Of T As ICounter)(x As T)
         Console.WriteLine(x.value)
         x.Increment()                     ' Modify x
         Console.WriteLine(x.value)
         CType(x, ICounter).Increment()    ' Modify boxed copy of x
         Console.WriteLine(x.value)
      End Sub

      Sub Main()
         Dim x As Counter
         Test(x)
      End Sub
End Module

Первый вызов Increment изменяет значение переменной x. Это не эквивалентно второму вызову Increment, который изменяет значение в запакованной копии x. Таким образом, выходные данные программы:

0
1
1

Преобразования типов значений, допускающих значение NULL

Тип T значения может преобразоваться в версию типа, допускаемую значением NULL, T?и из нее. Преобразование из T?T исключения вызывает System.InvalidOperationException исключение, если преобразуемое значение равно Nothing. Кроме того, имеет преобразование в типS, T? если T имеет встроенное преобразование Sв . И если S это тип значения, то между и S?следующими встроенными преобразованиями существуютT?:

  • Преобразование той же классификации (сужение или расширение) в T?S?.

  • Преобразование той же классификации (сужение или расширение) в TS?.

  • Сужающее преобразование из S?T.

Например, встроенное преобразование расширения существует из-за того, что встроенное расширение преобразования существует от Integer?IntegerLong?Long:

Dim i As Integer? = 10
Dim l As Long? = i

При преобразовании из T?S?, если значение T? равно Nothing, то значение S? будет Nothing. При преобразовании из S?ST?T или в , если значение T? или S? являетсяNothing, System.InvalidCastException создается исключение.

Из-за поведения базового типа System.Nullable(Of T), если задан тип значения T? , допускающего значение NULL, результатом является поле типа, а не прямоугольное значение Tтипа T?. И наоборот, при распаковке в тип T?значения, допускающего значение NULL, значение будет заключено в оболочку System.Nullable(Of T)и Nothing будет отсовернуто к значению NULL типа T?. Рассмотрим пример.

Dim i1? As Integer = Nothing
Dim o1 As Object = i1

Console.WriteLine(o1 Is Nothing)                    ' Will print True
o1 = 10
i1 = CType(o1, Integer?)
Console.WriteLine(i1)                               ' Will print 10

Побочным эффектом этого поведения является то, что тип T? значения, допускающий значение NULL, реализует все интерфейсы T, так как преобразование типа значения в интерфейс требует, чтобы тип отображался в поле. В результате T? преобразуется во все интерфейсы, в которые T можно преобразовать. Однако важно отметить, что тип T? значения, допускающего значение NULL, фактически не реализует интерфейсы T для целей проверки или отражения универсальных ограничений. Рассмотрим пример.

Interface I1
End Interface

Structure T1
    Implements I1
    ...
End Structure

Module Test
    Sub M1(Of T As I1)(ByVal x As T)
    End Sub

    Sub Main()
        Dim x? As T1 = Nothing
        Dim y As I1 = x                ' Valid
        M1(x)                          ' Error: x? does not satisfy I1 constraint
    End Sub
End Module

Преобразования строк

Char Преобразование в String результаты в строке, первая символ которой — это значение символа. String Преобразование в Char результаты в символе, значение которого является первым символом строки. Преобразование массива CharString в результаты в строку, символы которой являются элементами массива. Преобразование String в массив результатов в массив Char символов, элементы которых являются символами строки.

Точные преобразования между StringSingleULongLongIntegerDecimalDoubleBooleanSByteDateByteUShortShortUIntegerи , и наоборот, выходят за рамки этой спецификации и зависят от реализации за исключением одной детали. Преобразования строк всегда учитывают текущий язык и региональные параметры среды выполнения. Таким образом, они должны выполняться во время выполнения.

Расширение преобразований

Расширение преобразований никогда не переполнено, но может привести к потере точности. Следующие преобразования расширяются.

Преобразования удостоверений и значений по умолчанию

  • От типа к себе.

  • Из анонимного типа делегата, созданного для реклассификации лямбда-метода на любой тип делегата с идентичной подписью.

  • От литерала Nothing до типа.

Числовые преобразования

  • Byte UShort Short UInteger Integer ULong Long DecimalОт Single , или .Double

  • От SByte до Short, Integer, Long, Decimal, Singleили Double.

  • От UShort до UInteger, Integer, ULong, Long, Decimal, Singleили Double.

  • ОтShort, до Integer, DecimalLongSingle или .Double

  • От UInteger до ULong, Long, Decimal, Singleили Double.

  • От Integer до , DecimalSingle или Double.Long

  • От ULong до Decimal, Singleили Double.

  • От Long до Decimalили SingleDouble.

  • От Decimal до Single или Double.

  • От Single до Double.

  • От литерала 0 до перечисленного типа. (Примечание. Преобразование из 0 любого перечисленного типа расширяется, чтобы упростить тестирование флагов. Например, если Values это перечислимый тип со значением One, можно протестировать переменную v типа Values , сказав (v And Values.One) = 0.)

  • Из перечисленного типа в базовый числовый тип или в числовый тип, в который его базовый числовый тип имеет расширение преобразования.

  • Из константного выражения типа ULong, Long, IntegerShortByteUIntegerUShortили SByte более узкого типа, если значение константного выражения находится в диапазоне целевого типа. (Примечание. Преобразования из или в IntegerUIntegerSingle, ULong или DoubleLongSingle в, или в, или в или DecimalSingleDouble могут привести к потере точности, но никогда не приведет к потере величины. Другие расширенные числовые преобразования никогда не теряют никаких сведений.)

Ссылочные преобразования

  • От ссылочного типа к базовому типу.

  • Из ссылочного типа к типу интерфейса при условии, что тип реализует интерфейс или совместимый с вариантом интерфейс.

  • Из типа Objectинтерфейса в .

  • От типа интерфейса к типу интерфейса, совместимого с вариантом.

  • От типа делегата до типа делегата, совместимого с вариантом. (Примечание. Многие другие ссылочные преобразования подразумеваются этими правилами. Например, анонимные делегаты являются ссылочными типами, наследующими от System.MulticastDelegate; типы массивов являются ссылочными типами, наследуемыми System.Arrayот System.Object.)

Преобразования анонимных делегатов

  • Из анонимного типа делегата, созданного для реклассификации лямбда-метода на любой более широкий тип делегата.

Преобразования массивов

  • Из типа массива с типом элемента Se в тип ST массива с типом Teэлемента, если все следующие значения имеют значение true:

    • S и T отличаются только в типе элемента.

    • Оба Se типа и Te являются ссылочными типами или являются параметрами типа, известными как ссылочный тип.

    • Расширение ссылок, массива или преобразования параметров типа существует из SeTe.

  • Из типа массива с перечисленным типом Se элемента к типу S массива с типом TeT элемента, если все из следующих значений имеют значение true:

    • S и T отличаются только в типе элемента.

    • Te — базовый тип Se.

  • Из типа S массива 1 с перечисленным типом Seэлемента , в IReadOnlyList(Of Te)System.Collections.Generic.IList(Of Te), , ICollection(Of Te)IReadOnlyCollection(Of Te)иIEnumerable(Of Te), при условии, что одно из следующих значений имеет значение true:

    • Оба SeTe типа и являются ссылочными или являются параметрами типа, известными как ссылочный тип, и расширение ссылки, массива или преобразования параметров типа существует из SeTe; или

    • Te является базовым типом Se; или

    • Te идентичен Se

Преобразования типов значений

  • От типа значения до базового типа.

  • Из типа значения в тип интерфейса, реализуемого типом.

Преобразования типа значений, допускающих значение NULL

  • От типа к типу TT?.

  • От типа к типу T?S?, где имеется расширение преобразования от типа к типу TS.

  • От типа к типу TS?, где имеется расширение преобразования от типа к типу TS.

  • От типа к типу T? интерфейса, реализуемого типом T .

Преобразования строк

  • От Char до String.

  • От Char() до String.

Преобразования параметров типа

  • Из параметра Objectтипа в .

  • Из параметра типа в ограничение типа интерфейса или любой вариант интерфейса, совместимый с ограничением типа интерфейса.

  • Из параметра типа в интерфейс, реализованный ограничением класса.

  • Из параметра типа в вариант интерфейса, совместимый с интерфейсом, реализованным ограничением класса.

  • От параметра типа к ограничению класса или базовому типу ограничения класса.

  • Из параметра типа в ограничение Txпараметра T типа или что-либо Tx имеет расширение преобразования в.

Сужение преобразований

Сужающие преобразования — это преобразования, которые не могут быть всегда успешными, преобразования, которые, возможно, теряют информацию, и преобразования между доменами типов достаточно отличаются, чтобы заставить сузить нотацию. Следующие преобразования классифицируются как сужающие преобразования:

Логические преобразования

  • Boolean Byte SByte UShort Short UInteger Integer ULong Long DecimalОт Single , или .Double

  • От Byte, SByte, UShortULongDecimalLongSingleUIntegerIntegerShortили .DoubleBoolean

Числовые преобразования

  • От Byte до SByte.

  • От SByte до Byte, UShort, UIntegerили ULong.

  • От UShort до Byte, SByteили Short.

  • От Short до Byte, SByte, UShort, UIntegerили ULong.

  • От UInteger до Byte, SByte, UShort, Shortили Integer.

  • От Integer до Byte, SByte, UShort, Short, UIntegerили ULong.

  • От ULong до Byte, SByte, UShort, Short, UInteger, Integerили Long.

  • От Long до Byte, SByte, UShort, Short, UInteger, Integerили ULong.

  • От Decimal до Byte, SByte, UShort, Short, UInteger, Integer, ULongили Long.

  • Single Byte SByte UShort Short UInteger Integer ULongОт Long , или .Decimal

  • Double Byte SByte UShort Short UInteger Integer ULong LongОт Decimal , или .Single

  • От числового типа до перечисленного типа.

  • От перечисленного типа к числовой типу его базовый числовой тип имеет сужение преобразования в.

  • Из перечисленного типа в другой перечислимый тип.

Ссылочные преобразования

  • Из ссылочного типа в более производный тип.

  • Из типа класса в тип интерфейса, если тип класса не реализует тип интерфейса или вариант типа интерфейса, совместимый с ним.

  • Из типа интерфейса в тип класса.

  • Из типа интерфейса к другому типу интерфейса, если между двумя типами нет связи наследования и предоставлено, что они несовместимы.

Преобразования анонимных делегатов

  • Из анонимного типа делегата, созданного для реклассификации лямбда-метода на любой более узкий тип делегата.

Преобразования массивов

  • Из типа S массива с типом элемента Seдо типа T массива с типом Teэлемента, если все следующие значения имеют значение true:

    • S и T отличаются только в типе элемента.
    • Оба Se типа и Te являются ссылочными типами или являются параметрами типа, которые не известны как типы значений.
    • Сужающая ссылка, массив или преобразование параметров типа существует из SeTe.
  • Из типа массива с типом элемента Se в тип ST массива с перечисленным типом Teэлемента, если все следующие значения имеют значение true:

    • S и T отличаются только в типе элемента.
    • Se — это базовый Te тип или оба перечисленных типа, которые используют один и тот же базовый тип.
  • Из типа S массива 1 с перечисленным типом Seэлемента , в IList(Of Te), IReadOnlyList(Of Te)ICollection(Of Te)иIEnumerable(Of Te), IReadOnlyCollection(Of Te) при условии, что одно из следующих значений имеет значение true:

    • Оба SeTe типа и являются ссылочными или являются параметрами типа, известными как ссылочный тип, и сужающая ссылка, массив или преобразование параметров типа существует из SeTe; или
    • Se — это базовый Teтип или оба перечисленных типа, которые используют один и тот же базовый тип.

Преобразования типов значений

  • Из ссылочного типа в более производный тип значения.

  • Из типа интерфейса в тип значения, если тип значения реализует тип интерфейса.

Преобразования типа значений, допускающих значение NULL

  • От типа к типу T?T.

  • От типа к типу T?S?, где имеется сужающее преобразование из типа в тип TS.

  • От типа к типу TS?, где имеется сужающее преобразование из типа в тип TS.

  • От типа к типу S?T, где имеется преобразование из типа в тип ST.

Преобразования строк

  • От String до Char.

  • От String до Char().

  • От String до Boolean и StringотBoolean.

  • Преобразования между String и SByteShortUIntegerIntegerUShortByteLongDecimalULongSingle, или .Double

  • От String до Date и StringотDate.

Преобразования параметров типа

  • От Object параметра типа.

  • Из параметра типа в тип интерфейса, если параметр типа не ограничен этим интерфейсом или ограничен классом, реализующим этот интерфейс.

  • Из типа интерфейса в параметр типа.

  • Из параметра типа в производный тип ограничения класса.

  • Из параметра типа в любое ограничение Tx параметра T типа имеет сужение преобразования в.

Преобразования параметров типа

Преобразования параметров типа определяются ограничениями, если таковые имеются, помещаются в них. Параметр T типа всегда можно преобразовать в себя, в и из и из Objectлюбого типа интерфейса. Обратите внимание, что если тип является типом T значения во время выполнения, преобразование из TObject типа или типа интерфейса будет преобразованием в бокс и преобразованием из Object или типом интерфейса, которое T будет преобразованием в папку "Распаковка". Параметр типа с ограничением C класса определяет дополнительные преобразования из параметра типа в C базовые классы и наоборот. Параметр T типа с ограничением Tx параметра типа определяет преобразование и Tx все Tx , что преобразуется.

Массив, тип элемента которого является параметром типа с ограничением I интерфейса, имеет те же преобразования ковариантных массивов, что и массив, тип элемента которого имеется I, при условии, что параметр типа также имеет Class ограничение типа (так как только ссылочные типы элементов массива могут быть ковариантными). Массив, тип элемента которого является параметром типа с ограничением C класса, имеет те же преобразования ковариантных массивов, что и массив, тип элемента которого имеет тип Cэлемента.

Приведенные выше правила преобразования не позволяют преобразовании из параметров без ограничений типа в типы, не относящиеся к интерфейсу, что может быть удивительно. Причина этого заключается в том, чтобы предотвратить путаницу семантики таких преобразований. Например, рассмотрим следующее объявление:

Class X(Of T)
    Public Shared Function F(t As T) As Long 
        Return CLng(t)    ' Error, explicit conversion not permitted
    End Function
End Class

T Integer Если преобразование разрешено, можно было бы легко ожидать, что X(Of Integer).F(7) будет возвращено7L. Однако это не так, поскольку числовые преобразования считаются только в том случае, если типы известны как числовые во время компиляции. Чтобы сделать семантику ясной, приведенный выше пример должен быть написан:

Class X(Of T)
    Public Shared Function F(t As T) As Long
        Return CLng(CObj(t))    ' OK, conversions permitted
    End Function
End Class

преобразования User-Defined

Встроенные преобразования — это преобразования, определенные языком (т. е. перечисленными в этой спецификации), а определяемые пользователем преобразования определяются CType перегрузкой оператора. При преобразовании между типами, если встроенные преобразования не применяются, будут считаться определяемые пользователем преобразования. Если существует определяемое пользователем преобразование, наиболее конкретное для исходных и целевых типов, будет использоваться определяемое пользователем преобразование. В противном случае результаты ошибки во время компиляции. Наиболее конкретное преобразование — это тот, операнд которого является "ближайшим" к исходному типу и типом результатов которого является "ближайшим" к целевому типу. При определении используемого пользователем преобразования будет использоваться наиболее конкретное расширение; Если расширение не является наиболее конкретным, будет использоваться наиболее конкретное сужение преобразования. Если нет наиболее конкретного сужающего преобразования, преобразование не определено, и возникает ошибка во время компиляции.

В следующих разделах описывается определение наиболее конкретных преобразований. Они используют следующие термины:

Если встроенное расширение преобразования существует из типа в тип AB, и если ни ни BA интерфейсы, A то оно охватывается и BAохватываетсяB.

Наиболее охватывающий тип в наборе типов является один тип, охватывающий все остальные типы в наборе. Если один тип не охватывает все остальные типы, набор не имеет наиболее охватывающего типа. В интуитивно понятных терминах наиболее охватывающий тип является "крупнейшим" типом в наборе - один тип, в который можно преобразовать каждый из других типов путем расширения преобразования.

Наиболее охватываемый тип в наборе типов — это один тип, охватываемый всеми другими типами в наборе. Если ни один тип не охватывается всеми другими типами, то набор не имеет наиболее охватываемого типа. В интуитивно понятных терминах наиболее охватываемый тип является "наименьшим" типом в наборе - один тип, который можно преобразовать в каждый из остальных типов через сужение преобразования.

При сборе пользовательских преобразований для типа T?используются определяемые пользователем операторы T преобразования. Если преобразуемый тип также является типом значений, допускающим значение NULL, то удаляются любые Tпользовательские операторы преобразования, которые включают только типы значений, не допускающие значение NULL. Оператор TS преобразования, от которого выполняется, преобразуется в S?T? и вычисляется путем преобразования TT? в ,при необходимости, а затем вычисляется S определяемый пользователем оператор преобразования из TS и затем преобразуется в S?, если это необходимо. Если преобразуемое Nothingзначение равно, то оператор преобразования с поднятым значением преобразуется непосредственно в типизированное NothingS?значение. Рассмотрим пример.

Structure S
    ...
End Structure

Structure T
    Public Shared Widening Operator CType(ByVal v As T) As S
        ...
    End Operator
End Structure

Module Test
    Sub Main()
        Dim x As T?
        Dim y As S?

        y = x                ' Legal: y is still null
        x = New T()
        y = x                ' Legal: Converts from T to S
    End Sub
End Module

При разрешении преобразований определяемые пользователем операторы преобразования всегда предпочтительнее операторов преобразования с поднятым значением. Рассмотрим пример.

Structure S
    ...
End Structure

Structure T
    Public Shared Widening Operator CType(ByVal v As T) As S
        ...
    End Operator

    Public Shared Widening Operator CType(ByVal v As T?) As S?
        ...
    End Operator
End Structure

Module Test
    Sub Main()
        Dim x As T?
        Dim y As S?

        y = x                ' Calls user-defined conversion, not lifted conversion
    End Sub
End Module

Во время выполнения оценка определяемого пользователем преобразования может включать до трех шагов:

  1. Во-первых, значение преобразуется из исходного типа в тип операнда с помощью встроенного преобразования при необходимости.

  2. Затем вызывается определяемое пользователем преобразование.

  3. Наконец, результат пользовательского преобразования преобразуется в целевой тип с помощью встроенного преобразования при необходимости.

Важно отметить, что оценка определяемого пользователем преобразования никогда не будет включать несколько определяемых пользователем операторов преобразования.

Наиболее конкретное преобразование расширения

Определение наиболее конкретного определяемого пользователем оператора преобразования между двумя типами выполняется с помощью следующих действий.

  1. Во-первых, собираются все операторы преобразования кандидатов. Операторы преобразования кандидатов — это все определяемые пользователем операторы преобразования расширения в исходном типе и все определяемые пользователем операторы преобразования в целевом типе.

  2. Затем все не применимые операторы преобразования удаляются из набора. Оператор преобразования применим к исходному типу и целевому типу, если существует встроенный оператор расширения преобразования из исходного типа в тип операнда, и существует встроенный оператор расширения от результата оператора к целевому типу. Если нет применимых операторов преобразования, то нет наиболее конкретного преобразования расширения.

  3. Затем определяется наиболее конкретный тип источника применимых операторов преобразования:

    • Если любой из операторов преобразования преобразуется непосредственно из исходного типа, исходный тип является наиболее конкретным типом источника.

    • В противном случае наиболее конкретный тип источника — это наиболее охватываемый тип в объединенном наборе исходных типов операторов преобразования. Если не найдено наиболее охватываемого типа, то не существует наиболее конкретного преобразования расширения.

  4. Затем определяется наиболее конкретный целевой тип применимых операторов преобразования:

    • Если любой из операторов преобразования преобразуется непосредственно в целевой тип, то целевой тип является наиболее конкретным целевым типом.

    • В противном случае наиболее конкретный целевой тип является наиболее охватывающим типом в объединенном наборе целевых типов операторов преобразования. Если наиболее охватывающий тип не найден, то не существует наиболее конкретного преобразования расширения.

  5. Затем, если один оператор преобразования преобразуется из наиболее конкретного типа источника в наиболее конкретный целевой тип, то это самый конкретный оператор преобразования. Если существует несколько таких операторов, то нет наиболее конкретного преобразования расширения.

Наиболее конкретное сужение преобразования

Определение наиболее конкретного определяемого пользователем оператора сужения между двумя типами выполняется с помощью следующих действий.

  1. Во-первых, собираются все операторы преобразования кандидатов. Операторы преобразования кандидатов — это все определяемые пользователем операторы преобразования в исходном типе и все определяемые пользователем операторы преобразования в целевом типе.

  2. Затем все не применимые операторы преобразования удаляются из набора. Оператор преобразования применим к исходному типу и целевому типу, если имеется встроенный оператор преобразования из исходного типа в тип операнда, и есть встроенный оператор преобразования из результата оператора в целевой тип. Если нет применимых операторов преобразования, то не существует наиболее конкретного сужающего преобразования.

  3. Затем определяется наиболее конкретный тип источника применимых операторов преобразования:

    • Если любой из операторов преобразования преобразуется непосредственно из исходного типа, исходный тип является наиболее конкретным типом источника.

    • В противном случае, если любой из операторов преобразования преобразуется из типов, охватывающих тип источника, наиболее конкретный тип источника является наиболее охватывающимся в объединенном наборе исходных типов этих операторов преобразования. Если наиболее охватываемый тип не найден, то не существует наиболее конкретного сужения преобразования.

    • В противном случае наиболее конкретный исходный тип является наиболее охватывающим типом в объединенном наборе исходных типов операторов преобразования. Если наиболее охватывающий тип не найден, то не существует наиболее конкретного сужающего преобразования.

  4. Затем определяется наиболее конкретный целевой тип применимых операторов преобразования:

    • Если любой из операторов преобразования преобразуется непосредственно в целевой тип, то целевой тип является наиболее конкретным целевым типом.

    • В противном случае, если любой из операторов преобразования преобразуется в типы, охватываемые целевым типом, то наиболее конкретный целевой тип является наиболее охватывающим типом в объединенном наборе исходных типов этих операторов преобразования. Если наиболее охватывающий тип не найден, то не существует наиболее конкретного сужающего преобразования.

    • В противном случае наиболее конкретный целевой тип — это наиболее охватываемый тип в объединенном наборе целевых типов операторов преобразования. Если наиболее охватываемый тип не найден, то не существует наиболее конкретного сужения преобразования.

  5. Затем, если один оператор преобразования преобразуется из наиболее конкретного типа источника в наиболее конкретный целевой тип, то это самый конкретный оператор преобразования. Если существует несколько таких операторов, то преобразование сужается в большинстве случаев.

Собственные преобразования

Некоторые из преобразований классифицируются как собственные преобразования , так как они поддерживаются в собственном коде платформой .NET Framework. Эти преобразования — это те, которые можно оптимизировать с помощью DirectCast операторов и TryCast операторов преобразования, а также других специальных действий. Преобразования, классифицированные как собственные преобразования: преобразования удостоверений, преобразования по умолчанию, ссылочные преобразования, преобразования массивов, преобразования типов значений и преобразования параметров типа.

Доминирующий тип

Учитывая набор типов, часто требуется в таких ситуациях, как вывод типов, чтобы определить доминирующий тип набора. Доминирующий тип набора типов определяется путем первого удаления всех типов, в которых один или несколько других типов не имеют неявного преобразования. Если на данный момент нет типов, то доминирующий тип отсутствует. Затем доминирующий тип является наиболее охватывающим остальные типы. Если существует несколько типов, наиболее охватываемых, то доминирующий тип отсутствует.