変換とは、ある型から別の型に値を変更するプロセスです。 たとえば、Integer
型の値をDouble
型の値に変換したり、型Derived
の値をBase
型の値に変換したりできます。これは、Base
とDerived
の両方がクラスであり、Base
から継承Derived
と見なされます。 変換では、(後者の例のように) 値自体を変更する必要がない場合や、(前の例のように) 値表現を大幅に変更する必要がある場合があります。
変換は拡大または縮小のどちらでもかまいません。
拡大変換とは、型から別の型への変換で、値ドメインが少なくとも元の型の値ドメインよりも大きくても大きくない場合です。 拡大変換が失敗することはありません。
縮小変換とは、型から別の型への変換で、値ドメインが元の型の値ドメインよりも小さいか、変換を行うとき (たとえば、Integer
からString
に変換する場合) に特別な注意を払う必要があることを十分に関係がありません。 情報の損失を伴う可能性がある変換の縮小は失敗する可能性があります。
ID 変換 (つまり、型からそれ自体への変換) と既定値の変換 (つまり、 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
は、Byte
、255
UShort
の65535
、UInteger
の4294967295
、ULong
の18446744073709551615
、およびSByte
、Short
、Integer
、Long
、Decimal
、Single
、およびDouble
の式-1
に変換されます。 リテラル False
はリテラル 0
に変換されます。 数値が 0 の場合、リテラル False
に変換されます。 その他のすべての数値は、リテラル True
に変換されます。
ブール値から文字列への縮小変換があり、 System.Boolean.TrueString
または System.Boolean.FalseString
に変換されます。
String
からBoolean
への縮小変換もあります。文字列がTrueString
またはFalseString
(現在のカルチャでは大文字と小文字を区別せずに) と等しい場合は、適切な値を使用します。それ以外の場合は、文字列を数値型 (可能な場合は 16 進数または 8 進数)として解析し、上記の規則を使用します。それ以外の場合はSystem.InvalidCastException
をスローします。
数値変換
数値変換は、 Byte
、 SByte
、 UShort
、 Short
、 UInteger
、 Integer
、 ULong
、 Long
、 Decimal
、 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
数値変換は、実行時に次のように処理されます。
数値型からより広い数値型への変換の場合、値は単純に広い型に変換されます。
UInteger
、Integer
、ULong
、Long
、またはDecimal
からSingle
またはDouble
への変換は、最も近いSingle
またはDouble
値に丸められます。 この変換によって精度が失われる可能性はあり、桁違いになることはありません。整数型から別の整数型への変換、または整数型への
Single
、Double
、またはDecimal
からの変換の場合、結果は整数オーバーフロー チェックがオンかどうかによって異なります。整数オーバーフローがチェックされている場合:
ソースが整数型の場合、変換元の引数が変換先の型の範囲内にある場合、変換は成功します。 変換元の引数が変換先の型の範囲外の場合、
System.OverflowException
例外がスローされます。ソースが
Single
、Double
、またはDecimal
の場合、ソース値は最も近い整数値に切り上げられたり切り捨てられ、この整数値が変換の結果になります。 ソース値が 2 つの整数値に等しく近い場合、値は最下位桁の偶数の値に丸められます。 結果の整数値が変換先の型の範囲外の場合は、System.OverflowException
例外がスローされます。
整数オーバーフローがチェックされていない場合:
ソースが整数型の場合、変換は常に成功し、ソース値の最上位ビットを破棄するだけで構成されます。
ソースが
Single
、Double
、またはDecimal
の場合、変換は常に成功し、ソース値を最も近い整数値に丸めるだけで構成されます。 ソース値が 2 つの整数値に等しく近い場合、値は常に、最下位桁の偶数の値に丸められます。
Double
からSingle
への変換では、Double
値は最も近いSingle
値に丸められます。Double
値が小さすぎてSingle
として表すと、結果は正のゼロまたは負のゼロになります。Double
値が大きすぎてSingle
として表すと、結果は正の無限大または負の無限大になります。Double
値がNaN
場合、結果もNaN
。Single
またはDouble
からDecimal
への変換では、ソース値はDecimal
表現に変換され、必要に応じて小数点以下 28 桁目の後の最も近い数値に丸められます。 ソース値が小さすぎてDecimal
として表すと、結果は 0 になります。 ソース値がNaN
、無限大、または大きすぎてDecimal
として表すには、System.OverflowException
例外がスローされます。Double
からSingle
への変換では、Double
値は最も近いSingle
値に丸められます。Double
値が小さすぎてSingle
として表すと、結果は正のゼロまたは負のゼロになります。Double
値が大きすぎてSingle
として表すと、結果は正の無限大または負の無限大になります。Double
値がNaN
場合、結果もNaN
。
参照変換
参照型は基本型に変換でき、その逆も可能です。 基本型から派生型への変換は、変換される値が null 値、派生型自体、またはより多くの派生型である場合にのみ、実行時に成功します。
クラスとインターフェイスの型は、任意のインターフェイス型との間でキャストできます。 型とインターフェイス型の間の変換は、関係する実際の型に継承または実装リレーションシップがある場合にのみ、実行時に成功します。 インターフェイス型には常に、 Object
から派生した型のインスタンスが含まれるため、インターフェイス型は常に Object
との間でキャストすることもできます。
"注: COM クラスを表すクラスには実行時まで不明なインターフェイス実装がある可能性があるため、 NotInheritable
クラスを実装しないインターフェイスとの間で変換してもエラーではありません。
実行時に参照変換が失敗すると、 System.InvalidCastException
例外がスローされます。
参照分散変換
ジェネリック インターフェイスまたはデリゲートには、型の互換性のあるバリアント間の変換を可能にするバリアント型パラメーターがある場合があります。 したがって、実行時に、クラス型またはインターフェイス型から、継承または実装するインターフェイス型と互換性のあるバリアント型への変換は成功します。 同様に、デリゲート型は、バリアント互換デリゲート型との間でキャストできます。 たとえば、デリゲート型
Delegate Function F(Of In A, Out R)(a As A) As R
では、 F(Of Object, Integer)
から F(Of String, Integer)
への変換が可能になります。 つまり、Object
を受け取るデリゲート F
は、String
を受け取るデリゲート F
として安全に使用できます。 デリゲートが呼び出されると、ターゲット メソッドはオブジェクトを受け取り、文字列はオブジェクトになります。
ジェネリック デリゲート型またはインターフェイス型S(Of S1,...,Sn)
は、次の場合にT(Of T1,...,Tn)
ジェネリック インターフェイスまたはデリゲート型と互換性があるバリアント型と言われます。
S
T
はどちらも同じジェネリック型U(Of U1,...,Un)
から構築されます。各型パラメーターの
Ux
:型パラメーターが分散なしで宣言された場合、
Sx
とTx
は同じ型である必要があります。型パラメーターが
In
宣言されている場合は、Sx
からTx
への拡張 ID、既定、参照、配列、または型パラメーターの変換が必要です。型パラメーターが
Out
宣言されている場合は、Tx
からSx
への拡張 ID、既定、参照、配列、または型パラメーターの変換が必要です。
バリアント型パラメーターを使用してクラスからジェネリック インターフェイスに変換する場合、クラスが複数のバリアント互換インターフェイスを実装している場合、非バリアント変換がない場合、変換はあいまいになります。 例えば次が挙げられます。
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
の 2 つの型の場合、両方の参照型または型パラメーターが値型と見なされず、A
に参照、配列、または型パラメーターがB
に変換されている場合、A
型の配列から同じランクを持つB
型の配列への変換が存在します。 このリレーションシップは、 配列共分散と呼ばれます。 配列の共分散は、特に、要素型が B
配列の要素が、実際には要素型が A
配列の要素である可能性があることを意味します。ただし、 A
と B
の両方が参照型であり、 B
が参照変換または A
への配列変換を持っている場合です。 次の例では、F
の 2 番目の呼び出しでは、b
の実際の要素型がObject
ではなくString
されるため、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
のarray(i)
への代入には、変数value
によって参照されるオブジェクトがNothing
か、配列array
の実際の要素型と互換性のある型のインスタンスであることを確認する実行時チェックが暗黙的に含まれています。 メソッド Main
では、メソッドの最初の 2 つの呼び出しFill
成功しますが、3 番目の呼び出しでは、array(i)
への最初の割り当ての実行時にSystem.ArrayTypeMismatchException
例外がスローされます。 例外は、 Integer
を String
配列に格納できないために発生します。
配列要素型の 1 つが型パラメーターであり、その型が実行時に値型であることが判明した場合、 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
の配列は、Color
の基になる型Byte
の配列との間で変換されます。 ただし、Integer
はColor
の基になる型ではないため、Integer
の配列への変換はエラーになります。
A()
型の rank-1 配列には、System.Collections.Generic
で見つかったコレクション インターフェイス型IList(Of B)
、IReadOnlyList(Of B)
、ICollection(Of B)
、IReadOnlyCollection(Of B)
、IEnumerable(Of B)
への配列変換も含まれます。次のいずれかが当てはまる限りです。
-
A
およびB
は、参照型または値型として知られていない型パラメーターの両方です。また、A
には、拡大参照、配列、または型パラメーターからB
への変換があります。 -
A
およびB
は、どちらも同じ基になる型の列挙型です。 -
A
とB
の 1 つが列挙型で、もう 1 つは基になる型です。
任意のランクを持つ A 型の配列にも、System.Collections
で見つかった非ジェネリック コレクション インターフェイス型IList
、ICollection
、IEnumerable
への配列変換があります。
For Each
を使用するか、GetEnumerator
メソッドを直接呼び出すことによって、結果のインターフェイスを反復処理できます。 rank-1 配列の場合、 IList
または ICollection
のジェネリックまたは非ジェネリック形式に変換され、インデックスによって要素を取得することもできます。
IList
のジェネリックまたは非ジェネリック形式に変換されたランク 1 配列の場合は、上記と同じランタイム配列共分散チェックに従って、インデックスによって要素を設定することもできます。 他のすべてのインターフェイス メソッドの動作は、VB 言語仕様によって定義されていません。これは基になるランタイムにかかります。
値型の変換
値型の値は、ボックス 化と呼ばれるプロセスを通じて実装される基本参照型またはインターフェイス型のいずれかに変換できます。 値型の値がボックス化されると、値は .NET Framework ヒープに存在する場所からコピーされます。 その後、ヒープ上のこの場所への参照が返され、参照型変数に格納できます。 この参照は、値型の ボックス化された インスタンスとも呼ばれます。 ボックス化されたインスタンスには、値型ではなく参照型と同じセマンティクスがあります。
ボックス化された値型は、 ボックス化解除と呼ばれるプロセスを通じて元の値型に戻すことができます。 ボックス化された値型がボックス化解除されると、値はヒープから変数の場所にコピーされます。 その時点から、値型であるかのように動作します。 値型のボックス化を解除する場合、値は null 値または値型のインスタンスである必要があります。 それ以外の場合は、 System.InvalidCastException
例外がスローされます。 値が列挙型のインスタンスである場合、その値は、列挙型の基になる型または同じ基になる型を持つ別の列挙型にボックス化解除することもできます。 null 値は、リテラル Nothing
であるかのように扱われます。
null 許容値型を適切にサポートするために、 System.Nullable(Of T)
値型は、ボックス化とボックス化解除を行うときに特別に扱われます。
Nullable(Of T)
型の値をボックス化すると、値のHasValue
プロパティがTrue
されている場合はT
型のボックス化された値が、値のHasValue
プロパティがFalse
場合はNothing
の値になります。
T
型の値をボックス化解除してNullable(Of T)
すると、Value
プロパティがボックス化された値であり、HasValue
プロパティがTrue
Nullable(Of T)
のインスタンスになります。
Nothing
値は、任意のT
に対してNullable(Of T)
するようにボックス化解除でき、HasValue
プロパティがFalse
値になります。 ボックス化された値型は参照型と同様に動作するため、同じ値への複数の参照を作成できます。 プリミティブ型と列挙型の場合、これらの型のインスタンスは 不変であるため、これは関係ありません。 つまり、これらの型のボックス化されたインスタンスを変更することはできないため、同じ値への参照が複数あるという事実を観察することはできません。
一方、構造体は、そのインスタンス変数にアクセスできる場合や、そのメソッドまたはプロパティがそのインスタンス変数を変更する場合に変更可能な場合があります。 ボックス化された構造体への 1 つの参照を使用して構造を変更すると、ボックス化された構造体へのすべての参照に変更が表示されます。 この結果は予期しない可能性があるため、 Object
として型指定された値が 1 つの場所から別のボックス化された値型にコピーされると、参照がコピーされるのではなく、ヒープ上で自動的に複製されます。 例えば次が挙げられます。
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
ボックス化されたStruct1
がval2
に割り当てられたときに値のコピーが行われたため、ローカル変数val2
のフィールドへの代入は、ローカル変数val1
のフィールドには影響しません。 これに対し、割り当て ref2.Value = 123
は、 ref1
参照と ref2
参照の両方のオブジェクトに影響します。
"注:
System.ValueType
の遅延バインドができないため、System.ValueType
として型指定されたボックス化された構造体に対しては、構造体のコピーは行われません。
割り当て時にボックス化された値型がコピーされるというルールには例外が 1 つあります。 ボックス化された値型参照が別の型内に格納されている場合、内部参照はコピーされません。 例えば次が挙げられます。
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
の 2 回目の呼び出しと同じではありません。 したがって、プログラムの出力は次のようになります。
0
1
1
Null 許容値型変換
T
値型は、null 許容バージョンの型 (T?
) との間で変換できます。
T?
から T
への変換では、変換される値がNothing
された場合、System.InvalidOperationException
例外がスローされます。 また、T?
には、S
への組み込み変換がある場合T
S
型への変換があります。
S
が値型の場合は、T?
とS?
の間に次の組み込み変換が存在します。
同じ分類 (縮小または拡大) を
T?
からS?
に変換します。同じ分類 (縮小または拡大) を
T
からS?
に変換します。S?
からT
への縮小変換。
たとえば、組み込みの拡大変換は、Integer
からLong
への組み込みの拡大変換が存在するため、Integer?
からLong?
に存在します。
Dim i As Integer? = 10
Dim l As Long? = i
T?
からS?
に変換するときに、T?
の値がNothing
場合、S?
の値がNothing
されます。
S?
からT
またはT?
からS
に変換すると、T?
またはS?
の値がNothing
されると、System.InvalidCastException
例外がスローされます。
基になる型 System.Nullable(Of T)
の動作のため、null 許容値型 T?
ボックス化されると、結果は T
型のボックス化された値になります。 T?
型のボックス化された値ではありません。 逆に、null 許容値型 T?
にボックス化解除すると、値は System.Nullable(Of T)
でラップされ、 Nothing
は T?
型の null 値にボックス化解除されます。 例えば次が挙げられます。
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
この動作の副作用は、値型をインターフェイスに変換するには型をボックス化する必要があるため、null 許容値型T?
T
のすべてのインターフェイスを実装しているように見えるということです。 その結果、 T?
は、 T
変換可能なすべてのインターフェイスに変換できます。 ただし、null 許容値型 T?
では、ジェネリック制約チェックまたはリフレクションの目的で 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
とBoolean
、Byte
、SByte
、UShort
、Short
、UInteger
、Integer
、ULong
、Long
、Decimal
、Single
、Double
、Date
、およびその逆の間の正確な変換は、この仕様の範囲外であり、実装は 1 つの詳細を除いて依存します。 文字列変換では、実行時環境の現在のカルチャが常に考慮されます。 そのため、実行時に実行する必要があります。
拡大変換
拡大変換はオーバーフローすることはありませんが、精度が失われる可能性があります。 次の変換は拡大変換です。
ID/既定の変換
型からそれ自体へ。
ラムダ メソッドに対して生成された匿名デリゲート型から、同じシグネチャを持つ任意のデリゲート型に再分類します。
リテラル
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
、Long
、Decimal
、Single
、またはDouble
まで。UInteger
からULong
、Long
、Decimal
、Single
、またはDouble
。Integer
からLong
、Decimal
、Single
、またはDouble
まで。ULong
からDecimal
、Single
、またはDouble
。Long
からDecimal
、Single
、またはDouble
まで。Decimal
からSingle
またはDouble
。Single
からDouble
。リテラル
0
から列挙型へ。 (注。0
から任意の列挙型への変換は、フラグのテストを簡略化するために拡大されています。たとえば、Values
が値One
を持つ列挙型の場合は、(v And Values.One) = 0
と言ってValues
型の変数v
をテストできます)。列挙型から基になる数値型、または基になる数値型の拡大変換が行われる数値型。
定数式の値が変換先の型の範囲内であれば、
ULong
、Long
、UInteger
、Integer
、UShort
、Short
、Byte
、またはSByte
型の定数式から、より狭い型に変換されます。 (注。UInteger
またはInteger
からSingle
、ULong
、またはLong
からSingle
またはDouble
への変換、またはDecimal
からSingle
またはDouble
への変換は、精度の損失を引き起こす可能性がありますが、大きさが失われることはありません。他の拡大数値変換では、情報が失われることはありません)。
参照変換
参照型から基本型へ。
参照型からインターフェイス型まで(型がインターフェイスまたはバリアント互換インターフェイスを実装している場合)。
インターフェイスの種類から
Object
。インターフェイス型からバリアント互換インターフェイス型へ。
デリゲート型からバリアント互換デリゲート型へ。 (注。 他の多くの参照変換は、これらの規則によって暗黙的に示されます。たとえば、匿名デリゲートは
System.MulticastDelegate
から継承する参照型です。配列型はSystem.Array
から継承する参照型です。匿名型はSystem.Object
から継承する参照型です)。
匿名デリゲートの変換
- ラムダ メソッドに対して生成された匿名デリゲート型から、より広いデリゲート型への再分類。
配列変換
要素型
Se
を持つ配列型S
から、要素型Te
を持つ配列型T
まで、次のすべてが当てはまる場合。S
とT
は要素の種類でのみ異なります。Se
とTe
はどちらも参照型であるか、参照型と呼ばれる型パラメーターです。拡大参照、配列、または型パラメーターの変換は、
Se
からTe
に存在します。
列挙された要素型を持つ配列型
S
から、要素型Te
を持つ配列型T
にSe
。次のすべてが当てはまる場合。S
とT
は要素の種類でのみ異なります。Te
は、Se
の基になる型です。
列挙された要素型
Se
を持つランク 1 の配列型S
から、System.Collections.Generic.IList(Of Te)
、IReadOnlyList(Of Te)
、ICollection(Of Te)
、IReadOnlyCollection(Of Te)
、およびIEnumerable(Of Te)
に、次のいずれかが当てはまる場合。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
。型パラメーターからインターフェイス型制約、またはインターフェイス型制約と互換性のあるインターフェイスバリアントまで。
型パラメーターから、クラス制約によって実装されるインターフェイスまで。
型パラメーターから、クラス制約によって実装されるインターフェイスと互換性のあるインターフェイスバリアントまで。
型パラメーターからクラス制約、またはクラス制約の基本型。
型パラメーター
T
から型パラメーター制約Tx
、または拡大変換Tx
何か。
縮小変換
縮小変換とは、常に成功することが証明できない変換、情報が失われる可能性が知られている変換、および縮小表記のメリットを得るために十分に異なる型のドメイン間の変換です。 次の変換は縮小変換として分類されます。
ブール型変換
Boolean
からByte
、SByte
、UShort
、Short
、UInteger
、Integer
、ULong
、Long
、Decimal
、Single
、またはDouble
まで。Byte
、SByte
、UShort
、Short
、UInteger
、Integer
、ULong
、Long
、Decimal
、Single
、または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
まで。数値型から列挙型へ。
列挙型から数値型まで、基になる数値型には縮小変換があります。
列挙された型から別の列挙型へ。
参照変換
参照型からより派生型へ。
クラス型からインターフェイス型まで、クラス型に対応するインターフェイス型またはインターフェイス型バリアントが実装されていない場合。
インターフェイス型からクラス型へ。
2 つの型の間に継承関係がなく、バリアント互換性がない場合は、インターフェイス型から別のインターフェイス型へ。
匿名デリゲートの変換
- ラムダ メソッドに対して生成された匿名デリゲート型から、より狭いデリゲート型への再分類。
配列変換
要素型
Se
を持つ配列型S
から、要素型Te
を持つ配列型T
まで、次のすべてが当てはまる場合。-
S
とT
は要素の種類でのみ異なります。 -
Se
とTe
の両方が参照型であるか、値型として認識されていない型パラメーターです。 - 縮小参照、配列、または型パラメーターの変換は、
Se
からTe
に存在します。
-
要素型
Se
を持つ配列型S
から、列挙された要素型Te
を持つ配列型T
まで、次のすべてが当てはまる場合。-
S
とT
は要素の種類でのみ異なります。 -
Se
はTe
の基になる型です。または、両方とも同じ基になる型を共有する異なる列挙型です。
-
列挙された要素型
S
Se
を持つランク 1 の配列型から、IList(Of Te)
、IReadOnlyList(Of Te)
、ICollection(Of Te)
、IReadOnlyCollection(Of Te)
、IEnumerable(Of Te)
まで、次のいずれかが当てはまる場合。-
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
、Boolean
からString
まで。String
とByte
、SByte
、UShort
、Short
、UInteger
、Integer
、ULong
、Long
、Decimal
、Single
、またはDouble
の間の変換。String
からDate
、Date
からString
まで。
型パラメーターの変換
Object
から型パラメーターへ。型パラメーターからインターフェイス型まで、型パラメーターがそのインターフェイスに制約されていないか、そのインターフェイスを実装するクラスに制約されていない場合。
インターフェイス型から型パラメーターへ。
型パラメーターからクラス制約の派生型へ。
型パラメーター
T
から、縮小変換を持つ型パラメーター制約Tx
。
型パラメーターの変換
型パラメーターの変換は、制約 (存在する場合) によって決定されます。
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
への組み込みの拡大変換が存在し、A
もB
もインターフェイスでない場合、A
はB
とB
encompasses によって包含されますA
。
一連の型の 中で最も包含 型は、セット内の他のすべての型を含む 1 つの型です。 他のすべての型を含む型が 1 つもない場合、セットには最も包含される型はありません。 直感的に言うと、最も包括的な型は、セット内の "最大" 型です。つまり、他の各型を拡大変換で変換できる型です。
一連の型の 中で最も包含される 型は、セット内の他のすべての型に含まれる 1 つの型です。 他のすべての型に 1 つの型が含まれている場合、セットには最も包含される型はありません。 直感的に言えば、最も包含される型は、セット内の "最小" 型です。つまり、縮小変換を通じて他の型に変換できる型です。
型 T?
のユーザー定義変換候補を収集する場合は、 T
によって定義されたユーザー定義変換演算子が代わりに使用されます。 変換対象の型も null 許容値型である場合は、null 非許容値型のみを含む T
のユーザー定義変換演算子のいずれかが解除されます。
T
からS
への変換演算子は、T?
からS?
への変換にリフトされ、必要に応じてT?
からT
に変換し、必要に応じてユーザー定義の変換演算子をT
からS
に評価し、必要に応じてS
をS?
に変換することによって評価されます。 ただし、変換される値がNothing
の場合、リフトされた変換演算子は、S?
として型指定Nothing
値に直接変換します。 例えば次が挙げられます。
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
実行時に、ユーザー定義の変換を評価するには、最大 3 つの手順が必要な場合があります。
最初に、必要に応じて、値が組み込み変換を使用してソース型からオペランド型に変換されます。
次に、ユーザー定義の変換が呼び出されます。
最後に、必要に応じて、ユーザー定義変換の結果が組み込み変換を使用してターゲット型に変換されます。
ユーザー定義変換の評価には、複数のユーザー定義変換演算子が含まれることはありません。
最も具体的な拡大変換
2 つの型間で最も具体的なユーザー定義拡大変換演算子を決定するには、次の手順を使用します。
まず、すべての候補変換演算子が収集されます。 変換候補演算子は、ソース型のすべてのユーザー定義拡大変換演算子と、ターゲット型のすべてのユーザー定義拡大変換演算子です。
次に、該当しない変換演算子がすべてセットから削除されます。 変換演算子は、ソース型からオペランド型への拡張変換演算子が組み込まれており、演算子の結果からターゲット型への組み込みの拡大変換演算子がある場合に、ソース型とターゲット型に適用できます。 該当する変換演算子がない場合、最も具体的な拡大変換はありません。
次に、適用可能な変換演算子の最も具体的なソースの種類が決定されます。
変換演算子のいずれかがソース型から直接変換する場合、ソース型は最も具体的なソース型です。
それ以外の場合、最も具体的なソース型は、変換演算子のソース型の組み合わせの中で最も包含される型です。 最も包含される型が見つからない場合、最も具体的な拡大変換はありません。
次に、適用可能な変換演算子の最も具体的なターゲット型が決定されます。
変換演算子のいずれかがターゲット型に直接変換される場合、ターゲット型は最も具体的なターゲット型です。
それ以外の場合、最も具体的なターゲット型は、変換演算子のターゲット型の組み合わせの中で最も包括的な型です。 最も包含する型が見つからない場合は、最も具体的な拡大変換はありません。
次に、1 つの変換演算子が最も特定のソース型から最も特定のターゲット型に変換される場合、これが最も具体的な変換演算子になります。 このような演算子が複数存在する場合、最も具体的な拡大変換はありません。
最も具体的な縮小変換
2 つの型間で最も具体的なユーザー定義の縮小変換演算子を決定するには、次の手順を使用します。
まず、すべての候補変換演算子が収集されます。 変換候補演算子は、ソース型のすべてのユーザー定義変換演算子と、ターゲット型のすべてのユーザー定義変換演算子です。
次に、該当しない変換演算子がすべてセットから削除されます。 変換演算子は、ソース型からオペランド型への組み込み変換演算子があり、演算子の結果からターゲット型への組み込み変換演算子がある場合に、ソース型とターゲット型に適用できます。 該当する変換演算子がない場合、最も具体的な縮小変換はありません。
次に、適用可能な変換演算子の最も具体的なソースの種類が決定されます。
変換演算子のいずれかがソース型から直接変換する場合、ソース型は最も具体的なソース型です。
それ以外の場合、変換演算子のいずれかがソース型を含む型から変換される場合、最も具体的なソース型は、それらの変換演算子の結合されたソース型のセットの中で最も包含型になります。 最も包含される型が見つからない場合は、最も具体的な縮小変換はありません。
それ以外の場合、最も具体的なソース型は、変換演算子のソース型の組み合わせの中で最も包括的な型です。 最も包含する型が見つからない場合は、最も具体的な縮小変換はありません。
次に、適用可能な変換演算子の最も具体的なターゲット型が決定されます。
変換演算子のいずれかがターゲット型に直接変換される場合、ターゲット型は最も具体的なターゲット型です。
それ以外の場合、変換演算子のいずれかがターゲット型に含まれる型に変換される場合、最も具体的なターゲット型は、それらの変換演算子の結合されたソース型のセットの中で最も包含型になります。 最も包含する型が見つからない場合は、最も具体的な縮小変換はありません。
それ以外の場合、最も具体的なターゲット型は、変換演算子のターゲット型の組み合わせの中で最も包含される型です。 最も包含される型が見つからない場合は、最も具体的な縮小変換はありません。
次に、1 つの変換演算子が最も特定のソース型から最も特定のターゲット型に変換される場合、これが最も具体的な変換演算子になります。 このような演算子が複数存在する場合、最も具体的な縮小変換はありません。
ネイティブ変換
一部の変換は、.NET Framework でネイティブにサポートされているため、ネイティブ 変換 として分類されます。 これらの変換は、 DirectCast
および TryCast
変換演算子、およびその他の特殊な動作を使用して最適化できる変換です。 ネイティブ変換として分類される変換は、ID 変換、既定の変換、参照変換、配列変換、値型変換、型パラメーター変換です。
ドミナント型
型のセットを指定すると、多くの場合、セットの 主要な 型を決定するために型の推論などの状況で必要になります。 型のセットの主要な型は、最初に 1 つ以上の他の型が暗黙的な変換を持たない型を削除することによって決定されます。 この時点で型が残っていない場合、主要な型はありません。 その後、主要な型は、残りの型の中で最も包含されます。 最も包含されている型が複数ある場合、主な型はありません。
Visual Basic language spec