Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Преобразование — это процесс изменения значения с одного типа на другой. Например, значение типа Integer
можно преобразовать в значение типа, или значение типа Derived
Double
можно преобразовать в значение типа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
и не является числовым типом, он имеет сужающие преобразования в числовые типы и из них, как если бы это был перечислимый тип. Литерал преобразуется в литерал True
255
для Byte
, 65535
for UShort
, 4294967295
for UInteger
18446744073709551615
, for ULong
, и в выражение -1
для SByte
, , Long
Short
Decimal
Integer
Single
и .Double
Литерал преобразуется в литерал False
0
. Нулевое числовое значение преобразуется в литерал False
. Все остальные числовые значения преобразуются в литерал True
.
Существует сужающее преобразование из логического в string, преобразующееся в любой System.Boolean.TrueString
или System.Boolean.FalseString
. Также имеется сужение преобразования из String
Boolean
: если строка была равной TrueString
или FalseString
(в текущем языке и региональных параметрах, без учета регистра), то она использует соответствующее значение; в противном случае она пытается проанализировать строку как числовый тип (в шестнадцатеричном или восьмеричном, если это возможно, в противном случае как плавающее значение) и использует приведенные выше правила; в противном случае он вызывает System.InvalidCastException
.
Числовые преобразования
Числовые преобразования существуют между типамиByte
, Short
UInteger
Integer
UShort
SByte
Long
Decimal
ULong
Single
и 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
, илиULong
Long
вUInteger
илиDouble
Single
Decimal
округляются до ближайшегоSingle
илиDouble
значения. Хотя это преобразование может привести к потере точности, она никогда не приведет к потере величины.Для преобразования из целочисленного типа в другой целочисленный или из ,
Double
либоDecimal
вSingle
целочисленный тип, результат зависит от того, включена ли проверка целочисленного переполнения:Если выполняется проверка целочисленного переполнения:
Если источник является целочисленным типом, преобразование завершается успешно, если исходный аргумент находится в диапазоне целевого типа. Преобразование вызывает исключение, если исходный
System.OverflowException
аргумент находится за пределами диапазона целевого типа.Если источник имеет
Single
значение ,Double
илиDecimal
исходное значение округляется вверх или вниз до ближайшего целочисленного значения, и это целочисленное значение становится результатом преобразования. Если исходное значение равно близко к двум целочисленным значениям, значение округляется до значения, которое имеет четное число в наименьшей позиции цифры. Если результирующее целочисленное значение выходит за пределы диапазона целевого типа,System.OverflowException
создается исключение.
Если целочисленный переполнение не проверяется:
Если источник является целочисленным типом, преобразование всегда выполняется успешно и просто состоит из отмены наиболее значимых битов исходного значения.
Если источник имеет
Single
значение ,Double
илиDecimal
преобразование всегда выполняется успешно и просто состоит из округления исходного значения в сторону ближайшего целочисленного значения. Если исходное значение равно близко к двум целочисленным значениям, значение всегда округляется до значения, которое имеет четное число в наименьшей позиции цифры.
Для преобразования из
Double
Single
в ,Double
значение округляется до ближайшегоSingle
значения.Double
Если значение слишком мало для представления в видеSingle
, результат становится положительным нулем или отрицательным нулем.Double
Если значение слишком большое, чтобы представить в видеSingle
, результат становится положительным бесконечностью или отрицательным бесконечностью.Double
Если значение равноNaN
, результат такжеNaN
.Для преобразования из
Single
илиDouble
Decimal
в , исходное значение преобразуется вDecimal
представление и округляется до ближайшего числа после 28-го десятичного разряда при необходимости. Если исходное значение слишком мало для представления в видеDecimal
, результат становится нулевым. Если исходное значение равноNaN
, бесконечности или слишком большому для представления в видеDecimal
,System.OverflowException
создается исключение.Для преобразования из
Double
Single
в ,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
параметр типа, то должно быть расширение удостоверения, по умолчанию, ссылки, массива или преобразования параметров типа вSx
Tx
.Если был объявлен
Out
параметр типа, то должно быть расширение удостоверения, по умолчанию, ссылки, массива или преобразования параметров типа вTx
Sx
.
При преобразовании из класса в универсальный интерфейс с параметрами типа вариантов, если класс реализует несколько совместимых вариантов интерфейс преобразования неоднозначно, если преобразование не является вариантным. Рассмотрим пример.
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
, а не Object
System.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)
В методе первые два вызова метода Main
Fill
успешно, но третий вызов приводит 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
значение. Распаковка значения типа T
Nullable(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
Назначение для поля локальной переменной не влияет на поле локальной переменной val2
val1
, так как при назначении val2
поля Struct1
копия значения была сделана. В отличие от этого, назначение ref2.Value = 123
влияет на объект, который ref2
ref1
и ссылается.
Примечание. Копирование структуры не выполняется для прямоугольных структур, типизированных, так как 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?
.Преобразование той же классификации (сужение или расширение) в
T
S?
.Сужающее преобразование из
S?
T
.
Например, встроенное преобразование расширения существует из-за того, что встроенное расширение преобразования существует от Integer?
Integer
Long?
Long
:
Dim i As Integer? = 10
Dim l As Long? = i
При преобразовании из T?
S?
, если значение T?
равно Nothing
, то значение S?
будет Nothing
. При преобразовании из S?
S
T?
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
результаты в символе, значение которого является первым символом строки. Преобразование массива Char
String
в результаты в строку, символы которой являются элементами массива. Преобразование String
в массив результатов в массив Char
символов, элементы которых являются символами строки.
Точные преобразования между String
Single
ULong
Long
Integer
Decimal
Double
Boolean
SByte
Date
Byte
UShort
Short
UInteger
и , и наоборот, выходят за рамки этой спецификации и зависят от реализации за исключением одной детали. Преобразования строк всегда учитывают текущий язык и региональные параметры среды выполнения. Таким образом, они должны выполняться во время выполнения.
Расширение преобразований
Расширение преобразований никогда не переполнено, но может привести к потере точности. Следующие преобразования расширяются.
Преобразования удостоверений и значений по умолчанию
От типа к себе.
Из анонимного типа делегата, созданного для реклассификации лямбда-метода на любой тип делегата с идентичной подписью.
От литерала
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
,Decimal
Long
Single
или .Double
От
UInteger
доULong
,Long
,Decimal
,Single
илиDouble
.От
Integer
до ,Decimal
Single
илиDouble
.Long
От
ULong
доDecimal
,Single
илиDouble
.От
Long
доDecimal
илиSingle
Double
.От
Decimal
доSingle
илиDouble
.От
Single
доDouble
.От литерала
0
до перечисленного типа. (Примечание. Преобразование из0
любого перечисленного типа расширяется, чтобы упростить тестирование флагов. Например, еслиValues
это перечислимый тип со значениемOne
, можно протестировать переменнуюv
типаValues
, сказав(v And Values.One) = 0
.)Из перечисленного типа в базовый числовый тип или в числовый тип, в который его базовый числовый тип имеет расширение преобразования.
Из константного выражения типа
ULong
,Long
,Integer
Short
Byte
UInteger
UShort
илиSByte
более узкого типа, если значение константного выражения находится в диапазоне целевого типа. (Примечание. Преобразования из или вInteger
UInteger
Single
,ULong
илиDouble
Long
Single
в, или в, или в илиDecimal
Single
Double
могут привести к потере точности, но никогда не приведет к потере величины. Другие расширенные числовые преобразования никогда не теряют никаких сведений.)
Ссылочные преобразования
От ссылочного типа к базовому типу.
Из ссылочного типа к типу интерфейса при условии, что тип реализует интерфейс или совместимый с вариантом интерфейс.
Из типа
Object
интерфейса в .От типа интерфейса к типу интерфейса, совместимого с вариантом.
От типа делегата до типа делегата, совместимого с вариантом. (Примечание. Многие другие ссылочные преобразования подразумеваются этими правилами. Например, анонимные делегаты являются ссылочными типами, наследующими от
System.MulticastDelegate
; типы массивов являются ссылочными типами, наследуемымиSystem.Array
отSystem.Object
.)
Преобразования анонимных делегатов
- Из анонимного типа делегата, созданного для реклассификации лямбда-метода на любой более широкий тип делегата.
Преобразования массивов
Из типа массива с типом элемента
Se
в типS
T
массива с типомTe
элемента, если все следующие значения имеют значение true:S
иT
отличаются только в типе элемента.Оба
Se
типа иTe
являются ссылочными типами или являются параметрами типа, известными как ссылочный тип.Расширение ссылок, массива или преобразования параметров типа существует из
Se
Te
.
Из типа массива с перечисленным типом
Se
элемента к типуS
массива с типомTe
T
элемента, если все из следующих значений имеют значение 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:Оба
Se
Te
типа и являются ссылочными или являются параметрами типа, известными как ссылочный тип, и расширение ссылки, массива или преобразования параметров типа существует изSe
Te
; илиTe
является базовым типомSe
; илиTe
идентиченSe
Преобразования типов значений
От типа значения до базового типа.
Из типа значения в тип интерфейса, реализуемого типом.
Преобразования типа значений, допускающих значение NULL
От типа к типу
T
T?
.От типа к типу
T?
S?
, где имеется расширение преобразования от типа к типуT
S
.От типа к типу
T
S?
, где имеется расширение преобразования от типа к типуT
S
.От типа к типу
T?
интерфейса, реализуемого типомT
.
Преобразования строк
От
Char
доString
.От
Char()
доString
.
Преобразования параметров типа
Из параметра
Object
типа в .Из параметра типа в ограничение типа интерфейса или любой вариант интерфейса, совместимый с ограничением типа интерфейса.
Из параметра типа в интерфейс, реализованный ограничением класса.
Из параметра типа в вариант интерфейса, совместимый с интерфейсом, реализованным ограничением класса.
От параметра типа к ограничению класса или базовому типу ограничения класса.
Из параметра типа в ограничение
Tx
параметраT
типа или что-либоTx
имеет расширение преобразования в.
Сужение преобразований
Сужающие преобразования — это преобразования, которые не могут быть всегда успешными, преобразования, которые, возможно, теряют информацию, и преобразования между доменами типов достаточно отличаются, чтобы заставить сузить нотацию. Следующие преобразования классифицируются как сужающие преобразования:
Логические преобразования
Boolean
Byte
SByte
UShort
Short
UInteger
Integer
ULong
Long
Decimal
ОтSingle
, или .Double
От
Byte
,SByte
,UShort
ULong
Decimal
Long
Single
UInteger
Integer
Short
или .Double
Boolean
Числовые преобразования
От
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
являются ссылочными типами или являются параметрами типа, которые не известны как типы значений. - Сужающая ссылка, массив или преобразование параметров типа существует из
Se
Te
.
-
Из типа массива с типом элемента
Se
в типS
T
массива с перечисленным типом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:- Оба
Se
Te
типа и являются ссылочными или являются параметрами типа, известными как ссылочный тип, и сужающая ссылка, массив или преобразование параметров типа существует изSe
Te
; или -
Se
— это базовыйTe
тип или оба перечисленных типа, которые используют один и тот же базовый тип.
- Оба
Преобразования типов значений
Из ссылочного типа в более производный тип значения.
Из типа интерфейса в тип значения, если тип значения реализует тип интерфейса.
Преобразования типа значений, допускающих значение NULL
От типа к типу
T?
T
.От типа к типу
T?
S?
, где имеется сужающее преобразование из типа в типT
S
.От типа к типу
T
S?
, где имеется сужающее преобразование из типа в типT
S
.От типа к типу
S?
T
, где имеется преобразование из типа в типS
T
.
Преобразования строк
От
String
доChar
.От
String
доChar()
.От
String
доBoolean
иString
отBoolean
.Преобразования между
String
иSByte
Short
UInteger
Integer
UShort
Byte
Long
Decimal
ULong
Single
, или .Double
От
String
доDate
иString
отDate
.
Преобразования параметров типа
От
Object
параметра типа.Из параметра типа в тип интерфейса, если параметр типа не ограничен этим интерфейсом или ограничен классом, реализующим этот интерфейс.
Из типа интерфейса в параметр типа.
Из параметра типа в производный тип ограничения класса.
Из параметра типа в любое ограничение
Tx
параметраT
типа имеет сужение преобразования в.
Преобразования параметров типа
Преобразования параметров типа определяются ограничениями, если таковые имеются, помещаются в них. Параметр T
типа всегда можно преобразовать в себя, в и из и из Object
любого типа интерфейса. Обратите внимание, что если тип является типом T
значения во время выполнения, преобразование из T
Object
типа или типа интерфейса будет преобразованием в бокс и преобразованием из 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
перегрузкой оператора. При преобразовании между типами, если встроенные преобразования не применяются, будут считаться определяемые пользователем преобразования. Если существует определяемое пользователем преобразование, наиболее конкретное для исходных и целевых типов, будет использоваться определяемое пользователем преобразование. В противном случае результаты ошибки во время компиляции. Наиболее конкретное преобразование — это тот, операнд которого является "ближайшим" к исходному типу и типом результатов которого является "ближайшим" к целевому типу. При определении используемого пользователем преобразования будет использоваться наиболее конкретное расширение; Если расширение не является наиболее конкретным, будет использоваться наиболее конкретное сужение преобразования. Если нет наиболее конкретного сужающего преобразования, преобразование не определено, и возникает ошибка во время компиляции.
В следующих разделах описывается определение наиболее конкретных преобразований. Они используют следующие термины:
Если встроенное расширение преобразования существует из типа в тип A
B
, и если ни ни B
A
интерфейсы, A
то оно охватывается и B
A
охватываетсяB
.
Наиболее охватывающий тип в наборе типов является один тип, охватывающий все остальные типы в наборе. Если один тип не охватывает все остальные типы, набор не имеет наиболее охватывающего типа. В интуитивно понятных терминах наиболее охватывающий тип является "крупнейшим" типом в наборе - один тип, в который можно преобразовать каждый из других типов путем расширения преобразования.
Наиболее охватываемый тип в наборе типов — это один тип, охватываемый всеми другими типами в наборе. Если ни один тип не охватывается всеми другими типами, то набор не имеет наиболее охватываемого типа. В интуитивно понятных терминах наиболее охватываемый тип является "наименьшим" типом в наборе - один тип, который можно преобразовать в каждый из остальных типов через сужение преобразования.
При сборе пользовательских преобразований для типа T?
используются определяемые пользователем операторы T
преобразования. Если преобразуемый тип также является типом значений, допускающим значение NULL, то удаляются любые T
пользовательские операторы преобразования, которые включают только типы значений, не допускающие значение NULL. Оператор T
S
преобразования, от которого выполняется, преобразуется в S?
T?
и вычисляется путем преобразования T
T?
в ,при необходимости, а затем вычисляется S
определяемый пользователем оператор преобразования из T
S
и затем преобразуется в S?
, если это необходимо. Если преобразуемое Nothing
значение равно, то оператор преобразования с поднятым значением преобразуется непосредственно в типизированное Nothing
S?
значение. Рассмотрим пример.
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