Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
Преобразование — это процесс изменения значения с одного типа на другой. Например, значение типа 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до типа.
Числовые преобразования
ByteUShortShortUIntegerIntegerULongLongDecimalОт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имеет расширение преобразования в.
Сужение преобразований
Сужающие преобразования — это преобразования, которые не могут быть всегда успешными, преобразования, которые, возможно, теряют информацию, и преобразования между доменами типов достаточно отличаются, чтобы заставить сузить нотацию. Следующие преобразования классифицируются как сужающие преобразования:
Логические преобразования
BooleanByteSByteUShortShortUIntegerIntegerULongLongDecimalОт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.SingleByteSByteUShortShortUIntegerIntegerULongОтLong, или .DecimalDoubleByteSByteUShortShortUIntegerIntegerULongLongОт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
Во время выполнения оценка определяемого пользователем преобразования может включать до трех шагов:
Во-первых, значение преобразуется из исходного типа в тип операнда с помощью встроенного преобразования при необходимости.
Затем вызывается определяемое пользователем преобразование.
Наконец, результат пользовательского преобразования преобразуется в целевой тип с помощью встроенного преобразования при необходимости.
Важно отметить, что оценка определяемого пользователем преобразования никогда не будет включать несколько определяемых пользователем операторов преобразования.
Наиболее конкретное преобразование расширения
Определение наиболее конкретного определяемого пользователем оператора преобразования между двумя типами выполняется с помощью следующих действий.
Во-первых, собираются все операторы преобразования кандидатов. Операторы преобразования кандидатов — это все определяемые пользователем операторы преобразования расширения в исходном типе и все определяемые пользователем операторы преобразования в целевом типе.
Затем все не применимые операторы преобразования удаляются из набора. Оператор преобразования применим к исходному типу и целевому типу, если существует встроенный оператор расширения преобразования из исходного типа в тип операнда, и существует встроенный оператор расширения от результата оператора к целевому типу. Если нет применимых операторов преобразования, то нет наиболее конкретного преобразования расширения.
Затем определяется наиболее конкретный тип источника применимых операторов преобразования:
Если любой из операторов преобразования преобразуется непосредственно из исходного типа, исходный тип является наиболее конкретным типом источника.
В противном случае наиболее конкретный тип источника — это наиболее охватываемый тип в объединенном наборе исходных типов операторов преобразования. Если не найдено наиболее охватываемого типа, то не существует наиболее конкретного преобразования расширения.
Затем определяется наиболее конкретный целевой тип применимых операторов преобразования:
Если любой из операторов преобразования преобразуется непосредственно в целевой тип, то целевой тип является наиболее конкретным целевым типом.
В противном случае наиболее конкретный целевой тип является наиболее охватывающим типом в объединенном наборе целевых типов операторов преобразования. Если наиболее охватывающий тип не найден, то не существует наиболее конкретного преобразования расширения.
Затем, если один оператор преобразования преобразуется из наиболее конкретного типа источника в наиболее конкретный целевой тип, то это самый конкретный оператор преобразования. Если существует несколько таких операторов, то нет наиболее конкретного преобразования расширения.
Наиболее конкретное сужение преобразования
Определение наиболее конкретного определяемого пользователем оператора сужения между двумя типами выполняется с помощью следующих действий.
Во-первых, собираются все операторы преобразования кандидатов. Операторы преобразования кандидатов — это все определяемые пользователем операторы преобразования в исходном типе и все определяемые пользователем операторы преобразования в целевом типе.
Затем все не применимые операторы преобразования удаляются из набора. Оператор преобразования применим к исходному типу и целевому типу, если имеется встроенный оператор преобразования из исходного типа в тип операнда, и есть встроенный оператор преобразования из результата оператора в целевой тип. Если нет применимых операторов преобразования, то не существует наиболее конкретного сужающего преобразования.
Затем определяется наиболее конкретный тип источника применимых операторов преобразования:
Если любой из операторов преобразования преобразуется непосредственно из исходного типа, исходный тип является наиболее конкретным типом источника.
В противном случае, если любой из операторов преобразования преобразуется из типов, охватывающих тип источника, наиболее конкретный тип источника является наиболее охватывающимся в объединенном наборе исходных типов этих операторов преобразования. Если наиболее охватываемый тип не найден, то не существует наиболее конкретного сужения преобразования.
В противном случае наиболее конкретный исходный тип является наиболее охватывающим типом в объединенном наборе исходных типов операторов преобразования. Если наиболее охватывающий тип не найден, то не существует наиболее конкретного сужающего преобразования.
Затем определяется наиболее конкретный целевой тип применимых операторов преобразования:
Если любой из операторов преобразования преобразуется непосредственно в целевой тип, то целевой тип является наиболее конкретным целевым типом.
В противном случае, если любой из операторов преобразования преобразуется в типы, охватываемые целевым типом, то наиболее конкретный целевой тип является наиболее охватывающим типом в объединенном наборе исходных типов этих операторов преобразования. Если наиболее охватывающий тип не найден, то не существует наиболее конкретного сужающего преобразования.
В противном случае наиболее конкретный целевой тип — это наиболее охватываемый тип в объединенном наборе целевых типов операторов преобразования. Если наиболее охватываемый тип не найден, то не существует наиболее конкретного сужения преобразования.
Затем, если один оператор преобразования преобразуется из наиболее конкретного типа источника в наиболее конкретный целевой тип, то это самый конкретный оператор преобразования. Если существует несколько таких операторов, то преобразование сужается в большинстве случаев.
Собственные преобразования
Некоторые из преобразований классифицируются как собственные преобразования , так как они поддерживаются в собственном коде платформой .NET Framework. Эти преобразования — это те, которые можно оптимизировать с помощью DirectCast операторов и TryCast операторов преобразования, а также других специальных действий. Преобразования, классифицированные как собственные преобразования: преобразования удостоверений, преобразования по умолчанию, ссылочные преобразования, преобразования массивов, преобразования типов значений и преобразования параметров типа.
Доминирующий тип
Учитывая набор типов, часто требуется в таких ситуациях, как вывод типов, чтобы определить доминирующий тип набора. Доминирующий тип набора типов определяется путем первого удаления всех типов, в которых один или несколько других типов не имеют неявного преобразования. Если на данный момент нет типов, то доминирующий тип отсутствует. Затем доминирующий тип является наиболее охватывающим остальные типы. Если существует несколько типов, наиболее охватываемых, то доминирующий тип отсутствует.
Visual Basic language spec