次の方法で共有


Visual Basic での変換

変換とは、ある型から別の型に値を変更するプロセスです。 たとえば、Integer型の値をDouble型の値に変換したり、型Derivedの値をBase型の値に変換したりできます。これは、BaseDerivedの両方がクラスであり、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は、Byte255UShort65535UInteger4294967295ULong18446744073709551615、およびSByteShortIntegerLongDecimalSingle、およびDoubleの式-1に変換されます。 リテラル False はリテラル 0に変換されます。 数値が 0 の場合、リテラル Falseに変換されます。 その他のすべての数値は、リテラル Trueに変換されます。

ブール値から文字列への縮小変換があり、 System.Boolean.TrueString または System.Boolean.FalseStringに変換されます。 StringからBooleanへの縮小変換もあります。文字列がTrueStringまたはFalseString (現在のカルチャでは大文字と小文字を区別せずに) と等しい場合は、適切な値を使用します。それ以外の場合は、文字列を数値型 (可能な場合は 16 進数または 8 進数)として解析し、上記の規則を使用します。それ以外の場合はSystem.InvalidCastExceptionをスローします。

数値変換

数値変換は、 ByteSByteUShortShortUIntegerIntegerULongLongDecimalSingleDouble、およびすべての列挙型の間に存在します。 変換される場合、列挙型は基になる型であるかのように扱われます。 列挙型に変換する場合、ソース値は、列挙型で定義されている値のセットに準拠する必要はありません。 例えば次が挙げられます。

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

数値変換は、実行時に次のように処理されます。

  • 数値型からより広い数値型への変換の場合、値は単純に広い型に変換されます。 UIntegerIntegerULongLong、またはDecimalからSingleまたはDoubleへの変換は、最も近いSingleまたはDouble値に丸められます。 この変換によって精度が失われる可能性はあり、桁違いになることはありません。

  • 整数型から別の整数型への変換、または整数型への SingleDouble、または Decimal からの変換の場合、結果は整数オーバーフロー チェックがオンかどうかによって異なります。

    整数オーバーフローがチェックされている場合:

    • ソースが整数型の場合、変換元の引数が変換先の型の範囲内にある場合、変換は成功します。 変換元の引数が変換先の型の範囲外の場合、 System.OverflowException 例外がスローされます。

    • ソースが SingleDouble、または Decimalの場合、ソース値は最も近い整数値に切り上げられたり切り捨てられ、この整数値が変換の結果になります。 ソース値が 2 つの整数値に等しく近い場合、値は最下位桁の偶数の値に丸められます。 結果の整数値が変換先の型の範囲外の場合は、 System.OverflowException 例外がスローされます。

    整数オーバーフローがチェックされていない場合:

    • ソースが整数型の場合、変換は常に成功し、ソース値の最上位ビットを破棄するだけで構成されます。

    • ソースが SingleDouble、または 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:

    • 型パラメーターが分散なしで宣言された場合、 SxTx は同じ型である必要があります。

    • 型パラメーターが 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型自体はデリゲート型とは見なされないことに注意してください (すべてのデリゲート型がデリゲート型から継承されている場合でも)。 また、匿名デリゲート型から互換性のあるデリゲート型への変換は参照変換ではないことに注意してください。

配列変換

参照型であるという事実によって配列で定義される変換に加えて、配列にはいくつかの特別な変換が存在します。

ABの 2 つの型の場合、両方の参照型または型パラメーターが値型と見なされず、Aに参照、配列、または型パラメーターがBに変換されている場合、A型の配列から同じランクを持つB型の配列への変換が存在します。 このリレーションシップは、 配列共分散と呼ばれます。 配列の共分散は、特に、要素型が B 配列の要素が、実際には要素型が A配列の要素である可能性があることを意味します。ただし、 AB の両方が参照型であり、 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

この例では、メソッドFillarray(i)への代入には、変数valueによって参照されるオブジェクトがNothingか、配列arrayの実際の要素型と互換性のある型のインスタンスであることを確認する実行時チェックが暗黙的に含まれています。 メソッド Mainでは、メソッドの最初の 2 つの呼び出しFill成功しますが、3 番目の呼び出しでは、array(i)への最初の割り当ての実行時にSystem.ArrayTypeMismatchException例外がスローされます。 例外は、 IntegerString 配列に格納できないために発生します。

配列要素型の 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の配列との間で変換されます。 ただし、IntegerColorの基になる型ではないため、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 は、どちらも同じ基になる型の列挙型です。
  • ABの 1 つが列挙型で、もう 1 つは基になる型です。

任意のランクを持つ A 型の配列にも、System.Collectionsで見つかった非ジェネリック コレクション インターフェイス型IListICollectionIEnumerableへの配列変換があります。

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 プロパティがTrueNullable(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

ボックス化されたStruct1val2に割り当てられたときに値のコピーが行われたため、ローカル変数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.Valueval2.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

通常、ボックス化されたInteger5Byte変数にボックス化解除できませんでした。 ただし、 IntegerByte はプリミティブ型であり、変換があるため、変換は許可されます。

値型をインターフェイスに変換することは、インターフェイスに制約されているジェネリック引数とは異なされることに注意してください。 制約付き型パラメーター (または 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への組み込み変換がある場合TS型への変換があります。 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)でラップされ、 NothingT?型の 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

文字列変換

CharStringに変換すると、最初の文字が文字値である文字列になります。 StringCharに変換すると、値が文字列の最初の文字である文字になります。 Charの配列をStringに変換すると、配列の要素である文字を持つ文字列が作成されます。 StringCharの配列に変換すると、要素が文字列の文字である文字の配列が作成されます。

StringBooleanByteSByteUShortShortUIntegerIntegerULongLongDecimalSingleDoubleDate、およびその逆の間の正確な変換は、この仕様の範囲外であり、実装は 1 つの詳細を除いて依存します。 文字列変換では、実行時環境の現在のカルチャが常に考慮されます。 そのため、実行時に実行する必要があります。

拡大変換

拡大変換はオーバーフローすることはありませんが、精度が失われる可能性があります。 次の変換は拡大変換です。

ID/既定の変換

  • 型からそれ自体へ。

  • ラムダ メソッドに対して生成された匿名デリゲート型から、同じシグネチャを持つ任意のデリゲート型に再分類します。

  • リテラル Nothing から型へ。

数値変換

  • ByteからUShortShortUIntegerIntegerULongLongDecimalSingle、またはDoubleまで。

  • SByte から ShortIntegerLongDecimalSingle または Double

  • UShort から UIntegerIntegerULongLongDecimalSingle、または Double

  • ShortからIntegerLongDecimalSingle、またはDoubleまで。

  • UInteger から ULongLongDecimalSingle、または Double

  • IntegerからLongDecimalSingle、またはDoubleまで。

  • ULong から DecimalSingle、または Double

  • LongからDecimalSingle、またはDoubleまで。

  • Decimal から Single または Double

  • Single から Double

  • リテラル 0 から列挙型へ。 (注。0から任意の列挙型への変換は、フラグのテストを簡略化するために拡大されています。たとえば、Valuesが値Oneを持つ列挙型の場合は、(v And Values.One) = 0と言ってValues型の変数vをテストできます)。

  • 列挙型から基になる数値型、または基になる数値型の拡大変換が行われる数値型。

  • 定数式の値が変換先の型の範囲内であれば、 ULongLongUIntegerIntegerUShortShortByte、または SByte 型の定数式から、より狭い型に変換されます。 (注。UIntegerまたはIntegerからSingleULong、またはLongからSingleまたはDoubleへの変換、またはDecimalからSingleまたはDoubleへの変換は、精度の損失を引き起こす可能性がありますが、大きさが失われることはありません。他の拡大数値変換では、情報が失われることはありません)。

参照変換

  • 参照型から基本型へ。

  • 参照型からインターフェイス型まで(型がインターフェイスまたはバリアント互換インターフェイスを実装している場合)。

  • インターフェイスの種類から Object

  • インターフェイス型からバリアント互換インターフェイス型へ。

  • デリゲート型からバリアント互換デリゲート型へ。 (注。 他の多くの参照変換は、これらの規則によって暗黙的に示されます。たとえば、匿名デリゲートは System.MulticastDelegateから継承する参照型です。配列型は System.Arrayから継承する参照型です。匿名型は System.Objectから継承する参照型です)。

匿名デリゲートの変換

  • ラムダ メソッドに対して生成された匿名デリゲート型から、より広いデリゲート型への再分類。

配列変換

  • 要素型Seを持つ配列型Sから、要素型Teを持つ配列型Tまで、次のすべてが当てはまる場合。

    • ST は要素の種類でのみ異なります。

    • SeTeはどちらも参照型であるか、参照型と呼ばれる型パラメーターです。

    • 拡大参照、配列、または型パラメーターの変換は、 Se から Teに存在します。

  • 列挙された要素型を持つ配列型Sから、要素型Teを持つ配列型TSe。次のすべてが当てはまる場合。

    • ST は要素の種類でのみ異なります。

    • Te は、 Seの基になる型です。

  • 列挙された要素型Seを持つランク 1 の配列型Sから、System.Collections.Generic.IList(Of Te)IReadOnlyList(Of Te)ICollection(Of Te)IReadOnlyCollection(Of Te)、およびIEnumerable(Of Te)に、次のいずれかが当てはまる場合。

    • SeTeの両方が参照型であるか、参照型であることが知られている型パラメーターであり、拡大参照、配列、または型パラメーターの変換は、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からByteSByteUShortShortUIntegerIntegerULongLongDecimalSingle、またはDoubleまで。

  • ByteSByteUShortShortUIntegerIntegerULongLongDecimalSingle、またはDoubleからBoolean

数値変換

  • Byte から SByte

  • SByte から ByteUShortUInteger または ULong

  • UShort から ByteSByte、または Short

  • Short から ByteSByteUShortUInteger、または ULong

  • UInteger から ByteSByteUShortShort、または Integer

  • Integer から ByteSByteUShortShortUInteger または ULong

  • ULong から ByteSByteUShortShortUIntegerInteger、または Long

  • Long から ByteSByteUShortShortUIntegerInteger、または ULong

  • Decimal から ByteSByteUShortShortUIntegerIntegerULong または Long

  • SingleからByteSByteUShortShortUIntegerIntegerULongLong、またはDecimalまで。

  • DoubleからByteSByteUShortShortUIntegerIntegerULongLongDecimal、またはSingleまで。

  • 数値型から列挙型へ。

  • 列挙型から数値型まで、基になる数値型には縮小変換があります。

  • 列挙された型から別の列挙型へ。

参照変換

  • 参照型からより派生型へ。

  • クラス型からインターフェイス型まで、クラス型に対応するインターフェイス型またはインターフェイス型バリアントが実装されていない場合。

  • インターフェイス型からクラス型へ。

  • 2 つの型の間に継承関係がなく、バリアント互換性がない場合は、インターフェイス型から別のインターフェイス型へ。

匿名デリゲートの変換

  • ラムダ メソッドに対して生成された匿名デリゲート型から、より狭いデリゲート型への再分類。

配列変換

  • 要素型Seを持つ配列型Sから、要素型Teを持つ配列型Tまで、次のすべてが当てはまる場合。

    • ST は要素の種類でのみ異なります。
    • SeTeの両方が参照型であるか、値型として認識されていない型パラメーターです。
    • 縮小参照、配列、または型パラメーターの変換は、 Se から Teに存在します。
  • 要素型Seを持つ配列型Sから、列挙された要素型Teを持つ配列型Tまで、次のすべてが当てはまる場合。

    • ST は要素の種類でのみ異なります。
    • SeTe の基になる型です。または、両方とも同じ基になる型を共有する異なる列挙型です。
  • 列挙された要素型 SSeを持つランク 1 の配列型から、IList(Of Te)IReadOnlyList(Of Te)ICollection(Of Te)IReadOnlyCollection(Of Te)IEnumerable(Of Te)まで、次のいずれかが当てはまる場合。

    • SeTeの両方が参照型であるか、参照型であることが知られている型パラメーターであり、SeからTeへの縮小参照、配列、または型パラメーターの変換が存在します。
    • SeTeの基になる型です。または、両方とも同じ基になる型を共有する異なる列挙型です。

値型の変換

  • 参照型から、より派生した値型へ。

  • インターフェイス型から値型まで、値型がインターフェイス型を実装する場合。

Null 許容値型の変換

  • T? から型 T

  • T? から型 S?T 型から型 Sへの縮小変換があります。

  • T から型 S?T 型から型 Sへの縮小変換があります。

  • S? から型 Tに変換します。型 S から型 Tへの変換があります。

文字列変換

  • String から Char

  • String から Char()

  • StringからBooleanBooleanからStringまで。

  • StringByteSByteUShortShortUIntegerIntegerULongLongDecimalSingle、またはDoubleの間の変換。

  • StringからDateDateからStringまで。

型パラメーターの変換

  • Objectから型パラメーターへ。

  • 型パラメーターからインターフェイス型まで、型パラメーターがそのインターフェイスに制約されていないか、そのインターフェイスを実装するクラスに制約されていない場合。

  • インターフェイス型から型パラメーターへ。

  • 型パラメーターからクラス制約の派生型へ。

  • 型パラメーター T から、縮小変換を持つ型パラメーター制約 Tx

型パラメーターの変換

型パラメーターの変換は、制約 (存在する場合) によって決定されます。 T型パラメーターは、常に、任意のインターフェイス型との間で、Objectとの間で、それ自体に変換できます。 T型が実行時に値型である場合、TからObjectまたはインターフェイス型への変換はボックス化変換になり、Objectまたはインターフェイス型からTへの変換は、ボックス化解除変換になります。 クラス制約 C を持つ型パラメーターは、型パラメーターから C とその基底クラスへの追加の変換を定義します。その逆も同様です。 型パラメーター制約を持つ型パラメーターTTxTxへの変換と変換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への組み込みの拡大変換が存在し、ABもインターフェイスでない場合、ABBencompasses によって包含されますA

一連の型の 中で最も包含 型は、セット内の他のすべての型を含む 1 つの型です。 他のすべての型を含む型が 1 つもない場合、セットには最も包含される型はありません。 直感的に言うと、最も包括的な型は、セット内の "最大" 型です。つまり、他の各型を拡大変換で変換できる型です。

一連の型の 中で最も包含される 型は、セット内の他のすべての型に含まれる 1 つの型です。 他のすべての型に 1 つの型が含まれている場合、セットには最も包含される型はありません。 直感的に言えば、最も包含される型は、セット内の "最小" 型です。つまり、縮小変換を通じて他の型に変換できる型です。

T?のユーザー定義変換候補を収集する場合は、 T によって定義されたユーザー定義変換演算子が代わりに使用されます。 変換対象の型も null 許容値型である場合は、null 非許容値型のみを含む Tのユーザー定義変換演算子のいずれかが解除されます。 TからSへの変換演算子は、T?からS?への変換にリフトされ、必要に応じてT?からTに変換し、必要に応じてユーザー定義の変換演算子をTからSに評価し、必要に応じてSS?に変換することによって評価されます。 ただし、変換される値が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 つの手順が必要な場合があります。

  1. 最初に、必要に応じて、値が組み込み変換を使用してソース型からオペランド型に変換されます。

  2. 次に、ユーザー定義の変換が呼び出されます。

  3. 最後に、必要に応じて、ユーザー定義変換の結果が組み込み変換を使用してターゲット型に変換されます。

ユーザー定義変換の評価には、複数のユーザー定義変換演算子が含まれることはありません。

最も具体的な拡大変換

2 つの型間で最も具体的なユーザー定義拡大変換演算子を決定するには、次の手順を使用します。

  1. まず、すべての候補変換演算子が収集されます。 変換候補演算子は、ソース型のすべてのユーザー定義拡大変換演算子と、ターゲット型のすべてのユーザー定義拡大変換演算子です。

  2. 次に、該当しない変換演算子がすべてセットから削除されます。 変換演算子は、ソース型からオペランド型への拡張変換演算子が組み込まれており、演算子の結果からターゲット型への組み込みの拡大変換演算子がある場合に、ソース型とターゲット型に適用できます。 該当する変換演算子がない場合、最も具体的な拡大変換はありません。

  3. 次に、適用可能な変換演算子の最も具体的なソースの種類が決定されます。

    • 変換演算子のいずれかがソース型から直接変換する場合、ソース型は最も具体的なソース型です。

    • それ以外の場合、最も具体的なソース型は、変換演算子のソース型の組み合わせの中で最も包含される型です。 最も包含される型が見つからない場合、最も具体的な拡大変換はありません。

  4. 次に、適用可能な変換演算子の最も具体的なターゲット型が決定されます。

    • 変換演算子のいずれかがターゲット型に直接変換される場合、ターゲット型は最も具体的なターゲット型です。

    • それ以外の場合、最も具体的なターゲット型は、変換演算子のターゲット型の組み合わせの中で最も包括的な型です。 最も包含する型が見つからない場合は、最も具体的な拡大変換はありません。

  5. 次に、1 つの変換演算子が最も特定のソース型から最も特定のターゲット型に変換される場合、これが最も具体的な変換演算子になります。 このような演算子が複数存在する場合、最も具体的な拡大変換はありません。

最も具体的な縮小変換

2 つの型間で最も具体的なユーザー定義の縮小変換演算子を決定するには、次の手順を使用します。

  1. まず、すべての候補変換演算子が収集されます。 変換候補演算子は、ソース型のすべてのユーザー定義変換演算子と、ターゲット型のすべてのユーザー定義変換演算子です。

  2. 次に、該当しない変換演算子がすべてセットから削除されます。 変換演算子は、ソース型からオペランド型への組み込み変換演算子があり、演算子の結果からターゲット型への組み込み変換演算子がある場合に、ソース型とターゲット型に適用できます。 該当する変換演算子がない場合、最も具体的な縮小変換はありません。

  3. 次に、適用可能な変換演算子の最も具体的なソースの種類が決定されます。

    • 変換演算子のいずれかがソース型から直接変換する場合、ソース型は最も具体的なソース型です。

    • それ以外の場合、変換演算子のいずれかがソース型を含む型から変換される場合、最も具体的なソース型は、それらの変換演算子の結合されたソース型のセットの中で最も包含型になります。 最も包含される型が見つからない場合は、最も具体的な縮小変換はありません。

    • それ以外の場合、最も具体的なソース型は、変換演算子のソース型の組み合わせの中で最も包括的な型です。 最も包含する型が見つからない場合は、最も具体的な縮小変換はありません。

  4. 次に、適用可能な変換演算子の最も具体的なターゲット型が決定されます。

    • 変換演算子のいずれかがターゲット型に直接変換される場合、ターゲット型は最も具体的なターゲット型です。

    • それ以外の場合、変換演算子のいずれかがターゲット型に含まれる型に変換される場合、最も具体的なターゲット型は、それらの変換演算子の結合されたソース型のセットの中で最も包含型になります。 最も包含する型が見つからない場合は、最も具体的な縮小変換はありません。

    • それ以外の場合、最も具体的なターゲット型は、変換演算子のターゲット型の組み合わせの中で最も包含される型です。 最も包含される型が見つからない場合は、最も具体的な縮小変換はありません。

  5. 次に、1 つの変換演算子が最も特定のソース型から最も特定のターゲット型に変換される場合、これが最も具体的な変換演算子になります。 このような演算子が複数存在する場合、最も具体的な縮小変換はありません。

ネイティブ変換

一部の変換は、.NET Framework でネイティブにサポートされているため、ネイティブ 変換 として分類されます。 これらの変換は、 DirectCast および TryCast 変換演算子、およびその他の特殊な動作を使用して最適化できる変換です。 ネイティブ変換として分類される変換は、ID 変換、既定の変換、参照変換、配列変換、値型変換、型パラメーター変換です。

ドミナント型

型のセットを指定すると、多くの場合、セットの 主要な 型を決定するために型の推論などの状況で必要になります。 型のセットの主要な型は、最初に 1 つ以上の他の型が暗黙的な変換を持たない型を削除することによって決定されます。 この時点で型が残っていない場合、主要な型はありません。 その後、主要な型は、残りの型の中で最も包含されます。 最も包含されている型が複数ある場合、主な型はありません。