次の方法で共有


Visual Basic の式

式は、値の計算を指定するか、変数または定数を指定する演算子とオペランドのシーケンスです。 この章では、構文、オペランドと演算子の評価順序、および式の意味を定義します。

Expression
    : SimpleExpression
    | TypeExpression
    | MemberAccessExpression
    | DictionaryAccessExpression
    | InvocationExpression
    | IndexExpression
    | NewExpression
    | CastExpression
    | OperatorExpression
    | ConditionalExpression
    | LambdaExpression
    | QueryExpression
    | XMLLiteralExpression
    | XMLMemberAccessExpression
    ;

式の分類

すべての式は、次のいずれかとして分類されます。

  • 値。 すべての値には、型が関連付けられています。

  • 変数。 すべての変数には、変数の宣言された型という、関連付けられた型があります。

  • 名前空間。 この分類を持つ式は、メンバー アクセスの左側としてのみ表示できます。 その他のコンテキストでは、名前空間として分類された式によってコンパイル時エラーが発生します。

  • 型。 この分類を持つ式は、メンバー アクセスの左側としてのみ表示できます。 その他のコンテキストでは、型として分類された式によってコンパイル時エラーが発生します。

  • メソッド グループ。 同じ名前でオーバーロードされた一連のメソッドです。 メソッド グループには、ターゲット式と型引数リストが関連付けられている場合があります。

  • メソッド ポインター。メソッド の場所を表します。 メソッド ポインターには、関連付けられたターゲット式と、関連付けられた型引数リストが含まれる場合があります。

  • ラムダ メソッド。 これは匿名メソッドです。

  • プロパティ グループ。 同じ名前でオーバーロードされた一連のプロパティです。 プロパティ グループには、ターゲット式が関連付けられている場合があります。

  • プロパティ アクセス。 すべてのプロパティ アクセスには、関連付けられた型 (つまり、プロパティの型) があります。 プロパティ アクセスには、ターゲット式が関連付けられている場合があります。

  • 遅延バインディング アクセス。 実行時まで遅延されるメソッドまたはプロパティ アクセスを表します。 遅延バインディング アクセスには、関連付けられたターゲット式と、関連付けられた型引数リストが含まれる場合があります。 遅延バインディング アクセスの型は常に Object

  • イベント アクセス。 すべてのイベント アクセスには、関連付けられた型 (つまり、イベントの型) があります。 イベント アクセスには、ターゲット式が関連付けられている場合があります。 イベント アクセスは、 RaiseEventAddHandler、および RemoveHandler ステートメントの最初の引数として使用できます。 その他のコンテキストでは、イベント アクセスとして分類された式によってコンパイル時エラーが発生します。

  • 配列リテラル。 型がまだ決定されていない配列の初期値を表します。

  • 無効。 これは、式がサブルーチンの呼び出し、または結果のない await 演算子式である場合に発生します。 void として分類される式は、呼び出しステートメントまたは await ステートメントのコンテキストでのみ有効です。

  • 既定値。 リテラル Nothing のみがこの分類を生成します。

式の最終的な結果は通常、値または変数であり、式の他のカテゴリは、特定のコンテキストでのみ許可される中間値として機能します。

型パラメーターである式は、型パラメーターに課された制約がそれらの特性を満たしている場合に、式の型に特定の特性 (参照型、値型、何らかの型からの派生など) を必要とするステートメントや式で使用できます。

式の再分類

通常、式とは異なる分類を必要とするコンテキストで式を使用すると、コンパイル時エラーが発生します。たとえば、リテラルに値を割り当てようとします。 ただし、多くの場合、 再分類のプロセスを通じて式の分類を変更できます。

再分類が成功した場合、再分類は拡大または縮小と判断されます。 特に明記されていない限り、このリストのすべての再分類は拡大されています。

次の種類の式を再分類できます。

  • 変数は値として再分類できます。 変数に格納されている値がフェッチされます。

  • メソッド グループは値として再分類できます。 メソッド グループ式は、関連付けられたターゲット式と型パラメーター リストを持つ呼び出し式として解釈され、空のかっこ (つまり、 ff() として解釈され、 f(Of Integer)f(Of Integer)()として解釈されます)。 この再分類により、式がさらに void として再分類される可能性があります。

  • メソッド ポインターは、値として再分類できます。 この再分類は、ターゲット型が既知の変換のコンテキストでのみ発生します。 メソッド ポインター式は、関連付けられた型引数リストを持つ適切な型のデリゲートインスタンス化式の引数として解釈されます。 例えば次が挙げられます。

    Delegate Sub D(i As Integer)
    
    Module Test
        Sub F(i As Integer)
        End Sub
    
        Sub Main()
            Dim del As D
    
            ' The next two lines are equivalent.
            del = AddressOf F
            del = New D(AddressOf F)
        End Sub
    End Module
    
  • ラムダ メソッドは値として再分類できます。 変換のコンテキストで再分類が発生し、ターゲットの型がわかっている場合は、次の 2 つの再分類のいずれかが発生する可能性があります。

    1. ターゲット型がデリゲート型の場合、ラムダ メソッドは、適切な型のデリゲート構築式の引数として解釈されます。

    2. ターゲット型が System.Linq.Expressions.Expression(Of T)で、 T がデリゲート型の場合、ラムダ メソッドは、 T のデリゲート構築式で使用されているかのように解釈され、式ツリーに変換されます。

    非同期または反復子のラムダ メソッドは、デリゲートに ByRef パラメーターがない場合にのみ、デリゲート構築式の引数として解釈できます。

    デリゲートのいずれかのパラメーター型から対応するラムダ パラメーター型への変換が縮小変換である場合、再分類は縮小と判断されます。それ以外の場合は拡大しています。

    "注: ラムダ メソッドと式ツリー間の正確な変換は、コンパイラのバージョン間で修正できない可能性があり、この仕様の範囲外です。 Microsoft Visual Basic 11.0 の場合、すべてのラムダ式は、次の制限に従って式ツリーに変換できます。(1) 1。 ByRef パラメーターを持たない単一行ラムダ式のみを式ツリーに変換できます。 1 行 Sub ラムダのうち、呼び出しステートメントのみを式ツリーに変換できます。 (2) 以前のフィールド初期化子を使用して後続のフィールド初期化子 (例: New With {.a=1, .b=.a}) を初期化する場合、匿名型式を式ツリーに変換することはできません。 (3) 初期化中の現在のオブジェクトのメンバーがフィールド初期化子の 1 つ (例: New C1 With {.a=1, .b=.Method1()}) で使用されている場合、オブジェクト初期化子式を式ツリーに変換できません。 (4) 多次元配列作成式は、要素型を明示的に宣言する場合にのみ、式ツリーに変換できます。 (5) 遅延バインディング式を式ツリーに変換することはできません。 (6) 変数またはフィールドが ByRef を呼び出し式に渡されたが、ByRef パラメーターとまったく同じ型を持たない場合、またはプロパティが ByRef に渡された場合、通常の VB セマンティクスは引数のコピーが ByRef に渡され、その最終的な値が変数またはフィールドまたはプロパティにコピーされます。 式ツリーでは、コピー バックは行われません。 (7) これらすべての制限は、入れ子になったラムダ式にも適用されます。

    ターゲット型が不明な場合、ラムダ メソッドは、ラムダ メソッドの同じシグネチャを持つ匿名デリゲート型のデリゲートインスタンス化式の引数として解釈されます。 厳密なセマンティクスを使用していて、いずれかのパラメーターの型を省略すると、コンパイル時エラーが発生します。それ以外の場合、 Object は、パラメーターの型が不足している場合は置き換えされます。 例えば次が挙げられます。

    Module Test
        Sub Main()
            ' Type of x will be equivalent to Func(Of Object, Object, Object)
            Dim x = Function(a, b) a + b
    
            ' Type of y will be equivalent to Action(Of Object, Object)
            Dim y = Sub(a, b) Console.WriteLine(a + b)
        End Sub
    End Module
    
  • プロパティ グループは、プロパティ アクセスとして再分類できます。 プロパティ グループ式は、かっこが空のインデックス式として解釈されます (つまり、 ff()として解釈されます)。

  • プロパティ アクセスは、値として再分類できます。 プロパティ アクセス式は、プロパティの Get アクセサーの呼び出し式として解釈されます。 プロパティに getter がない場合は、コンパイル時エラーが発生します。

  • 遅延バインディング アクセスは、遅延バインディング メソッドまたは遅延バインディング プロパティ アクセスとして再分類できます。 遅延バインディング アクセスをメソッド アクセスとプロパティ アクセスの両方として再分類できる状況では、プロパティ アクセスへの再分類が推奨されます。

  • 遅延バインディング アクセスは、値として再分類できます。

  • 配列リテラルは値として再分類できます。 値の型は次のように決定されます。

    1. 変換のコンテキストで再分類が行われ、ターゲット型が配列型である場合、配列リテラルは T() 型の値として再分類されます。 ターゲット型が System.Collections.Generic.IList(Of T)IReadOnlyList(Of T)ICollection(Of T)IReadOnlyCollection(Of T)、または IEnumerable(Of T)であり、配列リテラルに 1 レベルの入れ子がある場合、配列リテラルは T()型の値として再分類されます。

    2. それ以外の場合、配列リテラルは、型が入れ子のレベルと等しいランクの配列である値に再分類され、要素型は初期化子内の要素の主要な型によって決定されます。主要な型を決定できない場合は、 Object が使用されます。 例えば次が挙げられます。

      ' x Is GetType(Double(,,))
      Dim x = { { { 1, 2.0 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } }.GetType()
      
      ' y Is GetType(Integer())
      Dim y = { 1, 2, 3 }.GetType()
      
      ' z Is GetType(Object())
      Dim z = { 1, "2" }.GetType()
      
      ' Error: Inconsistent nesting
      Dim a = { { 10 }, { 20, 30 } }.GetType()
      

    "注: バージョン 9.0 とバージョン 10.0 の言語の動作に若干の変更があります。 10.0 より前のバージョンでは、配列要素初期化子はローカル変数型の推論に影響を与えず、現在は影響を受けませんでした。 したがって、Dim a() = { 1, 2, 3 }は、バージョン 9.0 の言語とバージョン 10.0 のInteger()aの種類としてObject()を推論することになります。

    再分類により、配列リテラルが配列作成式として再解釈されます。 そのため、次の例を示します。

    Dim x As Double = { 1, 2, 3, 4 }
    Dim y = { "a", "b" }
    

    は次の内容に相当します。

    Dim x As Double = New Double() { 1, 2, 3, 4 }
    Dim y = New String() { "a", "b" }
    

    再分類は、要素式から配列要素型への変換が縮小されている場合に縮小と判断されます。それ以外の場合は拡大と判断されます。

  • 既定値 Nothing は、値として再分類できます。 ターゲット型がわかっているコンテキストでは、結果はターゲット型の既定値になります。 ターゲット型が不明なコンテキストでは、結果は Object 型の null 値になります。

名前空間式、型式、イベント アクセス式、または void 式を再分類することはできません。 複数の再分類を同時に行うことができます。 例えば次が挙げられます。

Module Test
    Sub F(i As Integer)
    End Sub

    ReadOnly Property P() As Integer
        Get
        End Get
    End Sub

    Sub Main()
        F(P)
    End Property
End Module

この場合、プロパティ グループ式 P は、最初にプロパティ グループからプロパティ アクセスに再分類され、次にプロパティ アクセスから値に再分類されます。 コンテキストで有効な分類に到達するために実行される再分類の数が最も少なくなります。

定数式

定数式は、コンパイル時に値を完全に評価できる式です。

ConstantExpression
    : Expression
    ;

定数式の型は、 ByteSByteUShortShortUIntegerIntegerULongLongCharSingleDoubleDecimalDateBooleanStringObject、または任意の列挙型です。 定数式では、次のコンストラクトを使用できます。

  • リテラル ( Nothingを含む)。

  • 定数型メンバーまたは定数ローカルへの参照。

  • 列挙型のメンバーへの参照。

  • かっこでつながれた部分式。

  • ターゲット型が上記のいずれかの型である場合、強制型式。 Stringとの間の強制変換はこのルールの例外であり、String変換は実行時に実行環境の現在のカルチャで常に実行されるため、null 値でのみ許可されます。 定数強制式では、組み込み変換のみを使用できることに注意してください。

  • オペランドと結果が上記の型である場合、 +- 、および単項演算子 Not

  • +-*^Mod/\<<>>&AndOrXorAndAlsoOrElse=<><><=、および=>二項演算子は、各オペランドと結果が上記の型で指定されています。

  • 条件演算子 If。各オペランドと結果が上記の型である場合。

  • 次のランタイム関数: Microsoft.VisualBasic.Strings.ChrW; 定数値が 0 から 128 の間の場合は Microsoft.VisualBasic.Strings.Chr 。定数文字列が空でない場合は Microsoft.VisualBasic.Strings.AscW 。定数文字列が空でない場合は Microsoft.VisualBasic.Strings.Asc

定数式では、次のコンストラクトは使用 できません

  • With コンテキストを介した暗黙的なバインド。

整数型 (ULongLongUIntegerIntegerUShortShortSByte、または Byte) の定数式は、より狭い整数型に暗黙的に変換でき、定数式の値が変換先の型の範囲内であれば、 Double 型の定数式を暗黙的に Singleに変換できます。 これらの縮小変換は、制限の緩いセマンティクスと厳密なセマンティクスのどちらが使用されているかに関係なく許可されます。

Late-Bound 式

メンバー アクセス式またはインデックス式のターゲットが Object型の場合、式の処理は実行時まで延期される可能性があります。 このように処理を遅延することは、 遅延バインディングと呼ばれます。 遅延バインディングを使用すると、 Object 変数を 型指定なしの 方法で使用できます。メンバーのすべての解決は、変数内の値の実際の実行時の型に基づいています。 コンパイル環境または Option Strictで厳密なセマンティクスを指定すると、遅延バインディングによってコンパイル時エラーが発生します。 オーバーロード解決の目的を含め、遅延バインディングを実行する場合、非パブリック メンバーは無視されます。 早期バインドの場合とは異なり、 Shared メンバーの遅延バインドを呼び出すかアクセスすると、呼び出しターゲットが実行時に評価されることに注意してください。 式が System.Objectで定義されているメンバーの呼び出し式である場合、遅延バインディングは行われません。

一般に、遅延バインディング アクセスは、式の実際の実行時の型の識別子を調べることによって、実行時に解決されます。 遅延バインディング メンバーの参照が実行時に失敗すると、 System.MissingMemberException 例外がスローされます。 遅延バインディング メンバーの参照は、関連付けられているターゲット式の実行時の型からのみ行われるため、オブジェクトのランタイム型はインターフェイスではありません。 そのため、遅延バインディング メンバー アクセス式のインターフェイス メンバーにアクセスすることはできません。

遅延バインディング メンバー アクセスの引数は、遅延バインディング メンバーでパラメーターが宣言される順序ではなく、メンバー アクセス式に表示される順序で評価されます。 次の例は、この違いを示しています。

Class C
    Public Sub f(ByVal x As Integer, ByVal y As Integer)
    End Sub
End Class

Module Module1
    Sub Main()
        Console.Write("Early-bound: ")
        Dim c As C = New C
        c.f(y:=t("y"), x:=t("x"))

        Console.Write(vbCrLf & "Late-bound: ")
        Dim o As Object = New C
        o.f(y:=t("y"), x:=t("x"))
    End Sub

    Function t(ByVal s As String) As Integer
        Console.Write(s)
        Return 0
    End Function
End Module

次のコードが表示されます。

Early-bound: xy
Late-bound: yx

遅延バインドオーバーロードの解決は引数の実行時の型で行われるため、式がコンパイル時または実行時に評価されるかどうかに基づいて異なる結果が生成される可能性があります。 次の例は、この違いを示しています。

Class Base
End Class

Class Derived
    Inherits Base
End Class

Module Test
    Sub F(b As Base)
        Console.WriteLine("F(Base)")
    End Sub

    Sub F(d As Derived)
        Console.WriteLine("F(Derived)")
    End Sub

    Sub Main()
        Dim b As Base = New Derived()
        Dim o As Object = b

        F(b)
        F(o)
    End Sub
End Module

次のコードが表示されます。

F(Base)
F(Derived)

単純式

単純式は、リテラル、かっこでつながれた式、インスタンス式、または単純な名前式です。

SimpleExpression
    : LiteralExpression
    | ParenthesizedExpression
    | InstanceExpression
    | SimpleNameExpression
    | AddressOfExpression
    ;

リテラル式

リテラル式は、リテラルによって表される値に評価されます。 リテラル式は、既定値として分類されるリテラル Nothingを除き、値として分類されます。

LiteralExpression
    : Literal
    ;

かっこで抽出された式

かっこで囲まれた式は、かっこで囲まれた式で構成されます。 かっこで囲まれた式は値として分類され、囲まれた式は値として分類される必要があります。 かっこで囲まれた式は、かっこ内の式の値に評価されます。

ParenthesizedExpression
    : OpenParenthesis Expression CloseParenthesis
    ;

インスタンス式

インスタンス式はキーワード Meです。 これは、非共有メソッド、コンストラクター、またはプロパティ アクセサーの本体内でのみ使用できます。 値として分類されます。 キーワード Me は、実行中のメソッドまたはプロパティ アクセサーを含む型のインスタンスを表します。 コンストラクターが別のコンストラクター (セクション コンストラクター) を明示的に呼び出す場合、インスタンスがまだ構築されていないため、そのコンストラクターの呼び出し後まで、 Me を使用できません。

InstanceExpression
    : 'Me'
    ;

単純な名前の式

単純な名前式は、1 つの識別子の後にオプションの型引数リストが続きます。

SimpleNameExpression
    : Identifier ( OpenParenthesis 'Of' TypeArgumentList CloseParenthesis )?
    ;

名前は解決され、次の "単純な名前解決規則" によって分類されます。

  1. 直ちに外側のブロックから開始し、外側の外側のブロック (存在する場合) を続けます。識別子がローカル変数、静的変数、定数 local、メソッド型パラメーター、またはパラメーターの名前と一致する場合、識別子は一致するエンティティを参照します。

    識別子がローカル変数、静的変数、または定数 local と一致し、型引数リストが指定された場合、コンパイル時エラーが発生します。 識別子がメソッド型パラメーターと一致し、型引数リストが指定された場合、一致は発生せず、解決が続行されます。 識別子がローカル変数と一致する場合、一致するローカル変数は暗黙的な関数または Get アクセサーがローカル変数を返し、式は呼び出し式、呼び出しステートメント、または AddressOf 式の一部であるため、一致は発生せず、解決が続行されます。

    式は、ローカル変数、静的変数、またはパラメーターである場合、変数として分類されます。 式がメソッド型パラメーターの場合、式は型として分類されます。 式が定数ローカルの場合、式は値として分類されます。

  2. 式を含む入れ子になった型ごとに、最も内側から最も外側に移動します。型内の識別子の検索によって、アクセス可能なメンバーとの一致が生成される場合は、次のようになります。

    1. 一致する型メンバーが型パラメーターの場合、結果は型として分類され、一致する型パラメーターになります。 型引数リストが指定された場合、一致は発生せず、解決が続行されます。
    2. それ以外の場合、型が直ちに外側の型で、ルックアップが非共有型メンバーを識別する場合、結果はフォーム Me.E(Of A)のメンバー アクセスと同じになります。ここで、 E は識別子、 A は型引数リスト (存在する場合) です。
    3. それ以外の場合、結果はフォーム T.E(Of A)のメンバー アクセスとまったく同じです。ここで、 T は一致するメンバーを含む型、 E は識別子、 A は型引数リスト (存在する場合) です。 この場合、識別子が非共有メンバーを参照するのはエラーです。
  3. 入れ子になった名前空間ごとに、最も内側から最も外側の名前空間に移動して、次の操作を行います。

    1. 名前空間に指定された名前のアクセス可能な型が含まれ、型引数リストで指定された型パラメーターの数が同じである場合、識別子はその型を参照し、型として分類されます。
    2. それ以外の場合、型引数リストが指定されておらず、名前空間に指定された名前の名前空間メンバーが含まれている場合、識別子はその名前空間を参照し、名前空間として分類されます。
    3. それ以外の場合、名前空間に 1 つ以上のアクセス可能な標準モジュールが含まれており、識別子のメンバー名の参照によってアクセス可能な一致が 1 つの標準モジュールで生成される場合、結果はフォーム M.E(Of A)のメンバー アクセスとまったく同じになります。ここで、 M は一致するメンバーを含む標準モジュール、 E は識別子、 A は型引数リストです。 存在する場合は 〗 識別子が複数の標準モジュールのアクセス可能な型メンバーと一致する場合は、コンパイル時エラーが発生します。
  4. ソース ファイルに 1 つ以上のインポート エイリアスがあり、その識別子がいずれかの名前と一致する場合、識別子はその名前空間または型を参照します。 型引数リストを指定すると、コンパイル時エラーが発生します。

  5. 名前参照を含むソース ファイルに 1 つ以上のインポートがある場合:

    1. 識別子が完全に 1 つのインポートで一致する場合は、型引数リストで指定された型パラメーターの数が同じアクセス可能な型の名前 (存在する場合)、または型メンバーが参照されます。識別子はその型または型メンバーを参照します。 識別子が複数のインポートで一致する場合、型引数リストで指定された型パラメーターの数が同じアクセス可能な型の名前 (存在する場合)、またはアクセス可能な型メンバーがある場合は、コンパイル時エラーが発生します。
    2. それ以外の場合、型引数リストが指定されておらず、識別子が一致する場合は、アクセス可能な型を持つ名前空間の名前がインポートされ、識別子はその名前空間を参照します。 型引数リストが指定されておらず、識別子が複数のインポートでアクセス可能な型を持つ名前空間の名前と一致する場合、コンパイル時エラーが発生します。
    3. それ以外の場合、インポートに 1 つ以上のアクセス可能な標準モジュールが含まれており、識別子のメンバー名参照によってアクセス可能な一致が 1 つの標準モジュールで生成される場合、結果はフォーム M.E(Of A)のメンバー アクセスとまったく同じになります。ここで、 M は一致するメンバーを含む標準モジュール、 E は識別子、 A は型引数リストです。 存在する場合は 〗 識別子が複数の標準モジュールのアクセス可能な型メンバーと一致する場合は、コンパイル時エラーが発生します。
  6. コンパイル環境で 1 つ以上のインポート エイリアスが定義されていて、その識別子がいずれかの名前と一致する場合、識別子はその名前空間または型を参照します。 型引数リストを指定すると、コンパイル時エラーが発生します。

  7. コンパイル環境で 1 つ以上のインポートが定義されている場合:

    1. 識別子が完全に 1 つのインポートで一致する場合は、型引数リストで指定された型パラメーターの数が同じアクセス可能な型の名前 (存在する場合)、または型メンバーが参照されます。識別子はその型または型メンバーを参照します。 識別子が複数のインポートで一致する場合は、型引数リストで指定された型パラメーターの数が同じアクセス可能な型の名前 (存在する場合) または型メンバーがインポートされると、コンパイル時エラーが発生します。
    2. それ以外の場合、型引数リストが指定されておらず、識別子が一致する場合は、アクセス可能な型を持つ名前空間の名前がインポートされ、識別子はその名前空間を参照します。 型引数リストが指定されておらず、識別子が複数のインポートでアクセス可能な型を持つ名前空間の名前と一致する場合、コンパイル時エラーが発生します。
    3. それ以外の場合、インポートに 1 つ以上のアクセス可能な標準モジュールが含まれており、識別子のメンバー名参照によってアクセス可能な一致が 1 つの標準モジュールで生成される場合、結果はフォーム M.E(Of A)のメンバー アクセスとまったく同じになります。ここで、 M は一致するメンバーを含む標準モジュール、 E は識別子、 A は型引数リストです。 存在する場合は 〗 識別子が複数の標準モジュールのアクセス可能な型メンバーと一致する場合は、コンパイル時エラーが発生します。
  8. それ以外の場合、識別子によって指定された名前は未定義です。

未定義の単純な名前式は、コンパイル時エラーです。

通常、名前は特定の名前空間で 1 回だけ行うことができます。 ただし、名前空間は複数の .NET アセンブリ間で宣言できるため、2 つのアセンブリが同じ完全修飾名を持つ型を定義する場合があります。 その場合、ソース ファイルの現在のセットで宣言されている型は、外部の .NET アセンブリで宣言されている型よりも優先されます。 それ以外の場合、名前はあいまいであり、名前を明確にする方法はありません。

AddressOf 式

AddressOf式は、メソッド ポインターを生成するために使用されます。 式は、 AddressOf キーワードと、メソッド グループまたは遅延バインディング アクセスとして分類する必要がある式で構成されます。 メソッド グループはコンストラクターを参照できません。

結果はメソッド ポインターとして分類され、メソッド グループと同じターゲット式と型引数リスト (存在する場合) が関連付けられます。

AddressOfExpression
    : 'AddressOf' Expression
    ;

型式

型式は、GetType式、TypeOf...Is式、Is式、またはGetXmlNamespace式です。

TypeExpression
    : GetTypeExpression
    | TypeOfIsExpression
    | IsExpression
    | GetXmlNamespaceExpression
    ;

GetType 式

GetType式は、キーワード GetTypeと型の名前で構成されます。

GetTypeExpression
    : 'GetType' OpenParenthesis GetTypeTypeName CloseParenthesis
    ;

GetTypeTypeName
    : TypeName
    | QualifiedOpenTypeName
    ;

QualifiedOpenTypeName
    : Identifier TypeArityList? (Period IdentifierOrKeyword TypeArityList?)*
    | 'Global' Period IdentifierOrKeyword TypeArityList?
      (Period IdentifierOrKeyword TypeArityList?)*
    ;

TypeArityList
    : OpenParenthesis 'Of' CommaList? CloseParenthesis
    ;

CommaList
    : Comma Comma*
    ;

GetType式は値として分類され、その値は GetTypeTypeName を表すリフレクション (System.Type) クラスです。 GetTypeTypeName が型パラメーターの場合、式は実行時に型パラメーターに指定された型引数に対応するSystem.Type オブジェクトを返します。

GetTypeTypeName は、次の 2 つの方法で特別です。

  • この型名を参照できる言語の唯一の場所である、 System.Voidすることが許可されています。

  • 型引数を省略して構築されたジェネリック型を指定できます。 これにより、 GetType 式は、ジェネリック型自体に対応する System.Type オブジェクトを返すことができます。

次の例では、 GetType 式を示します。

Module Test
    Sub Main()
        Dim t As Type() = { GetType(Integer), GetType(System.Int32), _
            GetType(String), GetType(Double()) }
        Dim i As Integer

        For i = 0 To t.Length - 1
            Console.WriteLine(t(i).Name)
        Next i
    End Sub
End Module

結果の出力は次のとおりです。

Int32
Int32
String
Double[]

TypeOf...Is Expressions

TypeOf...Is式は、値の実行時の型が特定の型と互換性があるかどうかを確認するために使用されます。 最初のオペランドは値として分類する必要があり、再分類されたラムダ メソッドにすることはできません。また、参照型または制約のない型パラメーター型である必要があります。 2 番目のオペランドは型名である必要があります。 式の結果は値として分類され、 Boolean 値になります。 この式は、オペランドの実行時の型が、型に対する ID、既定、参照、配列、値型、または型パラメーターの変換を持っている場合は True に評価 False 。それ以外の場合は、 式の型と特定の型の間に変換が存在しない場合、コンパイル時エラーが発生します。

TypeOfIsExpression
    : 'TypeOf' Expression 'Is' LineTerminator? TypeName
    ;

Is Expressions

参照等価比較を行うには、 Is 式または IsNot 式が使用されます。

IsExpression
    : Expression 'Is' LineTerminator? Expression
    | Expression 'IsNot' LineTerminator? Expression
    ;

各式は値として分類する必要があり、各式の型は参照型、制約されていない型パラメーター型、または null 許容値型である必要があります。 ただし、1 つの式の型が制約されていない型パラメーター型または null 許容値型である場合、もう 1 つの式はリテラル Nothingである必要があります。

結果は値として分類され、 Booleanとして入力されます。 Is操作は、両方の値が同じインスタンスを参照している場合、または両方の値がNothing場合はTrue、それ以外の場合はFalse評価されます。 IsNot操作は、両方の値が同じインスタンスを参照している場合、または両方の値がNothing場合はFalse、それ以外の場合はTrue評価されます。

GetXmlNamespace 式

GetXmlNamespace式は、キーワード GetXmlNamespaceと、ソース ファイルまたはコンパイル環境によって宣言された XML 名前空間の名前で構成されます。

GetXmlNamespaceExpression
    : 'GetXmlNamespace' OpenParenthesis XMLNamespaceName? CloseParenthesis
    ;

GetXmlNamespace式は値として分類され、その値は XMLNamespaceName を表すSystem.Xml.Linq.XNamespaceのインスタンスです。 その型が使用できない場合は、コンパイル時エラーが発生します。

例えば次が挙げられます。

Imports <xmlns:db="http://example.org/database">

Module Test
    Sub Main()
        Dim db = GetXmlNamespace(db)

        ' The following are equivalent
        Dim customer1 = _
            New System.Xml.Linq.XElement(db + "customer", "Bob")
        Dim customer2 = <db:customer>Bob</>
    End Sub
End Module

かっこの間はすべて名前空間名の一部と見なされるため、空白などの XML ルールが適用されます。 例えば次が挙げられます。

Imports <xmlns:db-ns="http://example.org/database">

Module Test
    Sub Main()

        ' Error, XML name expected
        Dim db1 = GetXmlNamespace( db-ns )

        ' Error, ')' expected
        Dim db2 = GetXmlNamespace(db _
            )

        ' OK.
        Dim db3 = GetXmlNamespace(db-ns)
    End Sub
End Module

XML 名前空間式は省略することもできます。この場合、式は既定の XML 名前空間を表すオブジェクトを返します。

メンバー アクセス式

メンバー アクセス式は、エンティティのメンバーにアクセスするために使用されます。

MemberAccessExpression
    : MemberAccessBase? Period IdentifierOrKeyword
      ( OpenParenthesis 'Of' TypeArgumentList CloseParenthesis )?
    ;

MemberAccessBase
    : Expression
    | NonArrayTypeName
    | 'Global'
    | 'MyClass'
    | 'MyBase'
    ;

フォーム E.I(Of A)のメンバー アクセス。 E は式、配列以外の型名、キーワードの Global、または省略され、 I は省略可能な型引数リスト Aを持つ識別子であり、評価され、次のように分類されます。

  1. Eを省略すると、すぐに含まれるWithステートメントの式がEに置き換わり、メンバー アクセスが実行されます。 含まれている With ステートメントがない場合は、コンパイル時エラーが発生します。

  2. Eが名前空間として分類されるか、Eがキーワード Globalである場合、メンバー参照は指定された名前空間のコンテキストで実行されます。 Iが型引数リストで指定されたのと同じ数の型パラメーターを持つ、その名前空間のアクセス可能なメンバーの名前である場合、結果はそのメンバーになります。 結果は、メンバーに応じて名前空間または型として分類されます。 それ以外の場合は、コンパイル時エラーが発生します。

  3. Eが型または型として分類された式である場合、メンバー参照は指定された型のコンテキストで実行されます。 IEのアクセス可能なメンバーの名前である場合、E.Iは評価され、次のように分類されます。

    1. Iがキーワード Newで、Eが列挙体でない場合は、コンパイル時エラーが発生します。
    2. Iが型引数リストで指定されたものと同じ数の型パラメーターを持つ型を識別する場合(存在する場合)、結果はその型になります。
    3. Iが 1 つ以上のメソッドを識別する場合、結果は、関連付けられた型引数リストを持つメソッド グループであり、ターゲット式は関連付けされません。
    4. Iが 1 つ以上のプロパティを識別し、型引数リストが指定されていない場合、結果はターゲット式が関連付けられていないプロパティ グループになります。
    5. Iが共有変数を識別し、型引数リストが指定されていない場合、結果は変数または値になります。 変数が読み取り専用で、変数が宣言されている型の共有コンストラクターの外部で参照が発生した場合、結果はEI共有変数の値になります。 それ以外の場合、結果はEI共有変数になります。
    6. Iが共有イベントを識別し、型引数リストが指定されていない場合、結果はターゲット式が関連付けられていないイベント アクセスになります。
    7. Iが定数を識別し、型引数リストが指定されていない場合、結果はその定数の値になります。
    8. Iが列挙型メンバーを識別し、型引数リストが指定されていない場合、結果はその列挙メンバーの値になります。
    9. それ以外の場合、 E.I は無効なメンバー参照であり、コンパイル時エラーが発生します。
  4. E変数または値として分類され、その型がT場合、メンバー参照はTのコンテキストで実行されます。 ITのアクセス可能なメンバーの名前である場合、E.Iは評価され、次のように分類されます。

    1. IキーワードがNewEMeMyBase、またはMyClassであり、型引数が指定されていない場合、結果は、Eの関連付けられたターゲット式と型引数リストのないEのインスタンス コンストラクターを表すメソッド グループになります。 それ以外の場合は、コンパイル時エラーが発生します。
    2. TObjectされていない場合に拡張メソッドを含む 1 つ以上のメソッドを識別I場合、結果は、関連付けられた型引数リストとEの関連するターゲット式を持つメソッド グループになります。
    3. Iが 1 つ以上のプロパティを識別し、型引数が指定されなかった場合、結果は、Eのターゲット式が関連付けられたプロパティ グループになります。
    4. Iが共有変数またはインスタンス変数を識別し、型引数が指定されていない場合、結果は変数または値になります。 変数が読み取り専用で、変数が変数の種類 (共有またはインスタンス) に適して宣言されているクラスのコンストラクターの外部で参照が発生した場合、結果は、Eによって参照されるオブジェクト内の変数Iの値になります。 Tが参照型の場合、結果はEによって参照されるオブジェクト内の変数Iになります。 それ以外の場合、 T が値型で、 E 式が変数として分類される場合、結果は変数になります。それ以外の場合、結果は値になります。
    5. Iがイベントを識別し、型引数が指定されなかった場合、結果は、Eの関連するターゲット式を使用したイベント アクセスになります。
    6. Iが定数を識別し、型引数が指定されていない場合、結果はその定数の値になります。
    7. Iが列挙型メンバーを識別し、型引数が指定されていない場合、結果はその列挙メンバーの値になります。
    8. TObject場合、結果は、関連付けられた型引数リストと、Eの関連するターゲット式を使用した遅延バインディング アクセスとして分類される遅延バインディング メンバー参照になります。
  5. それ以外の場合、 E.I は無効なメンバー参照であり、コンパイル時エラーが発生します。

フォーム MyClass.I(Of A) のメンバー アクセスは Me.I(Of A)と同じですが、そのフォームにアクセスするすべてのメンバーは、メンバーがオーバーライドできないかのように扱われます。 したがって、アクセスされるメンバーは、メンバーがアクセスされている値の実行時の型の影響を受けなくなります。

フォーム MyBase.I(Of A)のメンバー アクセスは、Tがメンバー アクセス式を含む型の直接基本型であるCType(Me, T).I(Of A)と同じです。 そのメソッドのすべての呼び出しは、呼び出されるメソッドがオーバーライドできないかのように扱われます。 この形式のメンバー アクセスは、 ベース アクセスとも呼ばれます。

次の例では、 MeMyBaseMyClass の関係を示します。

Class Base
    Public Overridable Sub F()
        Console.WriteLine("Base.F")
    End Sub
End Class

Class Derived
    Inherits Base

    Public Overrides Sub F()
        Console.WriteLine("Derived.F")
    End Sub

    Public Sub G()
        MyClass.F()
    End Sub
End Class

Class MoreDerived
    Inherits Derived

    Public Overrides Sub F()
        Console.WriteLine("MoreDerived.F")
    End Sub

    Public Sub H()
        MyBase.F()
    End Sub
End Class

Module Test
    Sub Main()
        Dim x As MoreDerived = new MoreDerived()

        x.F()
        x.G()
        x.H()
    End Sub

End Module

次のコードが出力されます。

MoreDerived.F
Derived.F
Derived.F

メンバー アクセス式がキーワード Global で始まる場合、キーワードは最も外側の名前のない名前空間を表します。これは、宣言が外側の名前空間をシャドウする状況で役立ちます。 Global キーワードを使用すると、その状況で最も外側の名前空間に "エスケープ" できます。 例えば次が挙げられます。

Class System
End Class

Module Test
    Sub Main()
        ' Error: Class System does not contain Console
        System.Console.WriteLine("Hello, world!") 


        ' Legal, binds to System in outermost namespace
        Global.System.Console.WriteLine("Hello, world!") 
    End Sub
End Module

上記の例では、識別子System名前空間Systemではなく、クラスSystemにバインドされるため、最初のメソッド呼び出しは無効です。 System名前空間にアクセスする唯一の方法は、Globalを使用して最も外側の名前空間にエスケープすることです。

アクセスされるメンバーが共有されている場合、期間の左側にある式は余分であり、メンバー アクセスが遅延バインドされない限り評価されません。 たとえば、次のコードを考えてみましょう。

Class C
    Public Shared F As Integer = 10
End Class

Module Test
    Public Function ReturnC() As C
        Console.WriteLine("Returning a new instance of C.")
        Return New C()
    End Function

    Public Sub Main()
        Console.WriteLine("The value of F is: " & ReturnC().F)
    End Sub
End Module

共有メンバー FにアクセスするためのCのインスタンスを提供するために関数ReturnCを呼び出す必要がないため、The value of F is: 10が出力されます。

同一の型とメンバー名

型と同じ名前を使用してメンバーに名前を付けるのは珍しくありません。 ただし、このような状況では、名前の非表示が不便な場合があります。

Enum Color
    Red
    Green
    Yellow
End Enum

Class Test
    ReadOnly Property Color() As Color
        Get
            Return Color.Red
        End Get
    End Property

    Shared Function DefaultColor() As Color
        Return Color.Green    ' Binds to the instance property!
    End Function
End Class

前の例では、DefaultColorの単純な名前Color型ではなくインスタンス プロパティにバインドされます。 インスタンス メンバーは共有メンバーで参照できないため、通常はエラーになります。

ただし、この場合は、特殊な規則によって型へのアクセスが許可されます。 メンバー アクセス式の基本式が単純な名前で、型が同じ名前の定数、フィールド、プロパティ、ローカル変数、またはパラメーターにバインドする場合、基本式はメンバーまたは型を参照できます。 どちらかのメンバーからアクセスできるメンバーが同じであるため、あいまいになることはありません。

既定のインスタンス

一部の状況では、共通の基底クラスから派生したクラスは、通常、または常に 1 つのインスタンスのみを持ちます。 たとえば、ユーザー インターフェイスに表示されるほとんどのウィンドウでは、常に 1 つのインスタンスのみが画面に表示されます。 これらの種類のクラスの操作を簡略化するために、Visual Basic では、各クラスに対して簡単に参照できる単一のインスタンスを提供するクラスの 既定 のインスタンスを自動的に生成できます。

既定のインスタンスは、1 つの特定の型ではなく、型の ファミリ に対して常に作成されます。 そのため、Form から派生する Form1 クラスの既定のインスタンスを作成する代わりに、Form から派生したすべてのクラスに対して既定のインスタンスが作成されます。 つまり、基底クラスから派生する個々のクラスは、既定のインスタンスを持つ特別なマークを付ける必要はありません。

クラスの既定のインスタンスは、そのクラスの既定のインスタンスを返すコンパイラによって生成されたプロパティによって表されます。 特定の基底クラスから派生したすべてのクラスの既定のインスタンスの割り当てと破棄を管理する グループ クラス と呼ばれるクラスのメンバーとして生成されるプロパティ。 たとえば、 Form から派生したクラスのすべての既定のインスタンス プロパティは、 MyForms クラスで収集できます。 式 My.Formsによってグループ クラスのインスタンスが返された場合、次のコードは、 Form1 および Form2派生クラスの既定のインスタンスにアクセスします。

Class Form1
    Inherits Form
    Public x As Integer
End Class

Class Form2
    Inherits Form
    Public y As Integer
End Class

Module Main
    Sub Main()
        My.Forms.Form1.x = 10
        Console.WriteLine(My.Forms.Form2.y)
    End Sub
End Module

既定のインスタンスは、それらに対する最初の参照まで作成されません。既定のインスタンスを表すプロパティをフェッチすると、既定のインスタンスがまだ作成されていないか、 Nothingに設定されている場合、既定のインスタンスが作成されます。 既定のインスタンスの存在をテストできるように、既定のインスタンスが Is または IsNot 演算子のターゲットである場合、既定のインスタンスは作成されません。 したがって、既定のインスタンスが作成されることなく、既定のインスタンスが Nothing されているか、または他の参照であるかをテストできます。

既定のインスタンスは、既定のインスタンスを持つクラスの外部から既定のインスタンスを簡単に参照できるようにするためのものです。 定義するクラス内から既定のインスタンスを使用すると、参照されるインスタンス (既定のインスタンスまたは現在のインスタンス) が混乱する可能性があります。 たとえば、次のコードは、別のインスタンスから呼び出されている場合でも、既定のインスタンスで x 値のみを変更します。 したがって、コードは10の代わりに5値を出力します。

Class Form1
    Inherits Form

    Public x As Integer = 5

    Public Sub ChangeX()
        Form1.x = 10
    End Sub
End Class

Module Main
    Sub Main()
        Dim f As Form1 = New Form1()
        f.ChangeX()
        Console.WriteLine(f.x)
    End Sub
End Module

このような混乱を防ぐために、既定のインスタンスの型のインスタンス メソッド内から既定のインスタンスを参照することは有効ではありません。

既定のインスタンスと型名

既定のインスタンスには、型の名前を使用して直接アクセスすることもできます。 この場合、型名が許可されていない式コンテキストでは、式 E (既定のインスタンスを持つクラスの完全修飾名を表す E ) が E'に変更されます。ここで、 E' は既定のインスタンス プロパティをフェッチする式を表します。 たとえば、 Form から派生したクラスの既定のインスタンスが型名を使用して既定のインスタンスにアクセスできるようにする場合、次のコードは前の例のコードと同じです。

Module Main
    Sub Main()
        Form1.x = 10
        Console.WriteLine(Form2.y)
    End Sub
End Module

これは、型の名前を使用してアクセスできる既定のインスタンスも、型名を介して割り当て可能であることを意味します。 たとえば、次のコードは、 Form1 の既定のインスタンスを Nothingに設定します。

Module Main
    Sub Main()
        Form1 = Nothing
    End Sub
End Module

E.Iの意味はEクラスを表し、Iは共有メンバーを表しますが、変更されないことに注意してください。 このような式は、クラス インスタンスから直接共有メンバーにアクセスし、既定のインスタンスを参照しません。

グループ クラス

Microsoft.VisualBasic.MyGroupCollectionAttribute属性は、既定のインスタンスのファミリのグループ クラスを示します。 この属性には、次の 4 つのパラメーターがあります。

  • パラメーター TypeToCollect は、グループの基底クラスを指定します。 (型パラメーターに関係なく) この名前を持つ型から派生した、開いている型パラメーターを持たないすべてのインスタント可能なクラスには、既定のインスタンスが自動的に含まれます。

  • パラメーター CreateInstanceMethodName は、グループ クラスで呼び出して、既定のインスタンス プロパティに新しいインスタンスを作成するメソッドを指定します。

  • パラメーター DisposeInstanceMethodName は、既定のインスタンス プロパティに値が Nothing割り当てられている場合に、グループ クラスで呼び出して既定のインスタンス プロパティを破棄するメソッドを指定します。

  • パラメーター DefaultInstanceAlias 、既定のインスタンスが型名を介して直接アクセスできる場合に、クラス名に置き換える式 E' を指定します。 このパラメーターが Nothing または空の文字列の場合、このグループ型の既定のインスタンスには、型の名前を使用して直接アクセスすることはできません。 (注。 Visual Basic 言語のすべての現在の実装では、コンパイラによって提供されるコードを除き、 DefaultInstanceAlias パラメーターは無視されます)。

最初の 3 つのパラメーターの型とメソッドの名前をコンマで区切ることで、複数の型を同じグループに収集できます。 各パラメーターには同じ数の項目が必要であり、リスト要素は順番に一致します。 たとえば、次の属性宣言は、 C1C2 、または C3 から派生した型を 1 つのグループに収集します。

<Microsoft.VisualBasic.MyGroupCollection("C1, C2, C3", _
    "CreateC1, CreateC2, CreateC3", _
    "DisposeC1, DisposeC2, DisposeC3", "My.Cs")>
Public NotInheritable Class MyCs
    ...
End Class

create メソッドのシグネチャは、 Shared Function <Name>(Of T As {New, <Type>})(Instance Of T) As T形式である必要があります。 dispose メソッドは、 Shared Sub <Name>(Of T As <Type>)(ByRef Instance Of T)形式である必要があります。 したがって、前のセクションの例のグループ クラスは、次のように宣言できます。

<Microsoft.VisualBasic.MyGroupCollection("Form", "Create", _
    "Dispose", "My.Forms")> _
Public NotInheritable Class MyForms
    Private Shared Function Create(Of T As {New, Form}) _
        (Instance As T) As T
        If Instance Is Nothing Then
            Return New T()
        Else
            Return Instance
        End If
    End Function

    Private Shared Sub Dispose(Of T As Form)(ByRef Instance As T)
        Instance.Close()
        Instance = Nothing
    End Sub
End Class

ソース ファイルが派生クラス Form1宣言した場合、生成されるグループ クラスは次のようになります。

<Microsoft.VisualBasic.MyGroupCollection("Form", "Create", _
    "Dispose", "My.Forms")> _
Public NotInheritable Class MyForms
    Private Shared Function Create(Of T As {New, Form}) _
        (Instance As T) As T
        If Instance Is Nothing Then
            Return New T()
        Else
            Return Instance
        End If
    End Function

    Private Shared Sub Dispose(Of T As Form)(ByRef Instance As T)
        Instance.Close()
        Instance = Nothing
    End Sub

    Private m_Form1 As Form1

    Public Property Form1() As Form1
        Get
            Return Create(m_Form1)
        End Get
        Set (Value As Form1)
            If Value IsNot Nothing AndAlso Value IsNot m_Form1 Then
                Throw New ArgumentException( _
                    "Property can only be set to Nothing.")
            End If
            Dispose(m_Form1)
        End Set
    End Property
End Class

Extension メソッド コレクション

メンバー アクセス式 E.I の拡張メソッドは、現在のコンテキストで使用できる名前 I を持つすべての拡張メソッドを収集することによって収集されます。

  1. まず、式を含む入れ子になった各型が、最も内側から最も外側に移動してチェックされます。
  2. 次に、入れ子になった各名前空間が、最も内側から最も外側の名前空間に移動してチェックされます。
  3. 次に、ソース ファイル内のインポートがチェックされます。
  4. 次に、コンパイル環境で定義されているインポートがチェックされます。

拡張メソッドは、ターゲット式の型から拡張メソッドの最初のパラメーターの型への拡大ネイティブ変換がある場合にのみ収集されます。 また、通常の単純な名前式バインドとは異なり、検索 ではすべての 拡張メソッドが収集されます。拡張メソッドが見つかると、コレクションは停止しません。 例えば次が挙げられます。

Imports System.Runtime.CompilerServices

Class C1
End Class


Namespace N1
    Module N1C1Extensions
        <Extension> _
        Sub M1(c As C1, x As Integer)
        End Sub
    End Module
End Namespace

Namespace N1.N2
    Module N2C1Extensions
        <Extension> _
        Sub M1(c As C1, y As Double)
        End Sub
    End Module
End Namespace

Namespace N1.N2.N3
    Module Test
        Sub Main()
            Dim x As New C1()

            ' Calls N1C1Extensions.M1
            x.M1(10)
        End Sub
    End Module
End Namespace

この例では、N1C1Extensions.M1する前にN2C1Extensions.M1が見つかった場合でも、両方とも拡張メソッドと見なされます。 すべての拡張メソッドが収集されると、それらは カリー化されます。 カリーリングは拡張メソッド呼び出しのターゲットを受け取り、それを拡張メソッド呼び出しに適用します。その結果、最初のパラメーターが削除された新しいメソッド シグネチャが生成されます (指定されているため)。 例えば次が挙げられます。

Imports System.Runtime.CompilerServices

Module Ext1
    <Extension> _
    Sub M(x As Integer, y As Integer)
    End Sub
End Module

Module Ext2
    <Extension> _
    Sub M(x As Integer, y As Double)
    End Sub
End Module

Module Main
    Sub Test()
        Dim v As Integer = 10

        ' The curried method signatures considered are:
        '        Ext1.M(y As Integer)
        '        Ext2.M(y As Double)
        v.M(10)
    End Sub
End Module

上記の例では、Ext1.Mvを適用した結果は、メソッド シグネチャのSub M(y As Integer)です。

カリー処理では、拡張メソッドの最初のパラメーターを削除するだけでなく、最初のパラメーターの型の一部であるメソッド型パラメーターも削除されます。 メソッド型パラメーターを使用して拡張メソッドをカリー化する場合、型推論が最初のパラメーターに適用され、推論されるすべての型パラメーターに対して結果が修正されます。 型の推論が失敗した場合、メソッドは無視されます。 例えば次が挙げられます。

Imports System.Runtime.CompilerServices

Module Ext1
    <Extension> _
    Sub M(Of T, U)(x As T, y As U)
    End Sub
End Module

Module Ext2
    <Extension> _
    Sub M(Of T)(x As T, y As T)
    End Sub
End Module

Module Main
    Sub Test()
        Dim v As Integer = 10

        ' The curried method signatures considered are:
        '        Ext1.M(Of U)(y As U)
        '        Ext2.M(y As Integer)
        v.M(10)
    End Sub
End Module

上記の例では、Ext1.Mvを適用した結果がメソッド シグネチャSub M(Of U)(y As U)です。型パラメーターTはカレー処理の結果として推論され、現在は修正されているためです。 型パラメーター U はカレー処理の一部として推論されていないため、開いているパラメーターのままです。 同様に、型パラメーターTExt2.Mvを適用した結果として推論されるため、パラメーターyの型はIntegerとして固定されます。 他の型であるとは推定されません。 シグネチャをカレーする場合、 New 制約を除くすべての制約も適用されます。 制約が満たされていない場合、またはカレー処理の一部として推論されなかった型に依存している場合、拡張メソッドは無視されます。 例えば次が挙げられます。

Imports System.Runtime.CompilerServices

Module Ext1
    <Extension> _
    Sub M1(Of T As Structure)(x As T, y As Integer)
    End Sub

    <Extension> _
    Sub M2(Of T As U, U)(x As T, y As U)
    End Sub
End Module

Module Main
    Sub Test()
        Dim s As String = "abc"

        ' Error: String does not satisfy the Structure constraint
        s.M1(10)

        ' Error: T depends on U, which cannot be inferred
        s.M2(10)
    End Sub
End Module

"注: 拡張メソッドのカリー処理を実行する主な理由の 1 つは、クエリ パターン メソッドに対する引数を評価する前に、クエリ式がイテレーションの型を推論できるようにするためです。 ほとんどのクエリ パターン メソッドは、型推論自体を必要とするラムダ式を受け取るので、クエリ式を評価するプロセスが大幅に簡略化されます。

通常のインターフェイス継承とは異なり、相互に関連しない 2 つのインターフェイスを拡張する拡張メソッドは、同じカリー化されたシグネチャがない限り使用できます。

Imports System.Runtime.CompilerServices

Interface I1
End Interface

Interface I2
End Interface

Class C1
    Implements I1, I2
End Class

Module I1Ext
    <Extension> _
    Sub M1(i As I1, x As Integer)
    End Sub

    <Extension> _
    Sub M2(i As I1, x As Integer)
    End Sub
End Module

Module I2Ext
    <Extension> _
    Sub M1(i As I2, x As Integer)
    End Sub

    <Extension> _
    Sub M2(I As I2, x As Double)
    End Sub
End Module

Module Main
    Sub Test()
        Dim c As New C1()

        ' Error: M is ambiguous between I1Ext.M1 and I2Ext.M1.
        c.M1(10)

        ' Calls I1Ext.M2
        c.M2(10)
    End Sub
End Module

最後に、遅延バインディングを実行するときに拡張メソッドは考慮されないことに注意することが重要です。

Module Test
    Sub Main()
        Dim o As Object = ...

        ' Ignores extension methods
        o.M1()
    End Sub
End Module

Dictionary メンバー アクセス式

ディクショナリ メンバー アクセス式は、コレクションのメンバーを検索するために使用されます。 ディクショナリ メンバー アクセスは、 E!Iの形式になります。ここで、 E は値として分類される式であり、 I は識別子です。

DictionaryAccessExpression
    : Expression? '!' IdentifierOrKeyword
    ;

式の型には、1 つの String パラメーターでインデックスが付いた既定のプロパティが必要です。 ディクショナリ メンバーアクセス式 E!I は式 E.D("I")に変換されます。ここで、 DEの既定のプロパティです。 例えば次が挙げられます。

Class Keys
    Public ReadOnly Default Property Item(s As String) As Integer
        Get
            Return 10
        End Get
    End Property 
End Class

Module Test
    Sub Main()
        Dim x As Keys = new Keys()
        Dim y As Integer
        ' The two statements are equivalent.
        y = x!abc
        y = x("abc")
    End Sub
End Module

感嘆符が式なしで指定されている場合、すぐに含まれる With ステートメントからの式が想定されます。 含まれている With ステートメントがない場合は、コンパイル時エラーが発生します。

呼び出し式

呼び出し式は、呼び出しターゲットと省略可能な引数リストで構成されます。

InvocationExpression
    : Expression ( OpenParenthesis ArgumentList? CloseParenthesis )?
    ;

ArgumentList
    : PositionalArgumentList
    | PositionalArgumentList Comma NamedArgumentList
    | NamedArgumentList
    ;

PositionalArgumentList
    : Expression? ( Comma Expression? )*
    ;

NamedArgumentList
    : IdentifierOrKeyword ColonEquals Expression
      ( Comma IdentifierOrKeyword ColonEquals Expression )*
    ;

ターゲット式は、メソッド グループまたは型がデリゲート型の値として分類する必要があります。 ターゲット式がデリゲート型の値である場合、呼び出し式のターゲットはデリゲート型の Invoke メンバーのメソッド グループになり、ターゲット式はメソッド グループの関連付けられたターゲット式になります。

引数リストには、位置引数と名前付き引数の 2 つのセクションがあります。 位置引数 は式であり、名前付き引数の前に置く必要があります。 名前付き引数は 、キーワードに一致する識別子から始まり、その後に := と式が続きます。

メソッド グループに、インスタンスメソッドと拡張メソッドの両方を含む、アクセス可能なメソッドが 1 つだけ含まれており、そのメソッドが引数を受け取っていない場合、メソッド グループは空の引数リストを持つ呼び出し式として解釈され、結果は指定された引数リストを持つ呼び出し式のターゲットとして使用されます。 例えば次が挙げられます。

Class C1
    Function M1() As Integer()
        Return New Integer() { 1, 2, 3 }
    End Sub
End Class

Module Test
    Sub Main()
        Dim c As New C1()

        ' Prints 3
        Console.WriteLine(c.M1(2))
    End Sub
End Module

それ以外の場合、オーバーロードの解決がメソッドに適用され、指定された引数リストに最も適用可能なメソッドが選択されます。 最も適用可能なメソッドが関数の場合、呼び出し式の結果は、関数の戻り値の型として型指定された値として分類されます。 最も適用可能な方法がサブルーチンの場合、結果は void として分類されます。 最も適用可能なメソッドが本文のない部分メソッドの場合、呼び出し式は無視され、結果は void として分類されます。

事前バインドされた呼び出し式の場合、引数は、ターゲット メソッドで対応するパラメーターが宣言されている順序で評価されます。 遅延バインディング メンバー アクセス式については、メンバー アクセス式に表示される順序で評価されます。セクション Late-Bound 式を参照してください。

オーバーロードされたメソッドの解決:

オーバーロードの解決については、引数リスト、ジェネリック性、引数リストへの適用性、引数の受け渡し、および省略可能なパラメーター、条件付きメソッド、および型引数の推論の引数の選択を指定した場合のメンバー/型の特定性については、「 オーバーロードの解決」セクションを参照してください。

インデックス式

インデックス式を使用すると、配列要素が作成されるか、プロパティ グループがプロパティ アクセスに再分類されます。 インデックス式は、式、始めかっこ、インデックス引数リスト、および終わりかっこで構成されます。

IndexExpression
    : Expression OpenParenthesis ArgumentList? CloseParenthesis
    ;

インデックス式のターゲットは、プロパティ グループまたは値として分類する必要があります。 インデックス式は次のように処理されます。

  • ターゲット式が値として分類され、その型が配列型、 Object、または System.Arrayでない場合、型には既定のプロパティが必要です。 インデックスは、型のすべての既定のプロパティを表すプロパティ グループに対して実行されます。 Visual Basic でパラメーターなしの既定のプロパティを宣言することは有効ではありませんが、他の言語ではこのようなプロパティを宣言できる場合があります。 その結果、引数のないプロパティのインデックス作成が許可されます。

  • 式の結果が配列型の値になる場合、引数リスト内の引数の数は配列型のランクと同じである必要があり、名前付き引数を含めてはなりません。 実行時にいずれかのインデックスが無効な場合は、 System.IndexOutOfRangeException 例外がスローされます。 各式は、 Integer型に暗黙的に変換できる必要があります。 インデックス式の結果は、指定したインデックスの変数であり、変数として分類されます。

  • 式がプロパティ グループとして分類されている場合、オーバーロードの解決を使用して、いずれかのプロパティがインデックス引数リストに適用されるかどうかを判断します。 プロパティ グループに Get アクセサーを持つプロパティが 1 つだけ含まれている場合、そのアクセサーが引数を受け取っていない場合、プロパティ グループは空の引数リストを持つインデックス式として解釈されます。 結果は、現在のインデックス式のターゲットとして使用されます。 該当するプロパティがない場合は、コンパイル時エラーが発生します。 それ以外の場合、式は、プロパティ グループの関連付けられたターゲット式 (存在する場合) を使用してプロパティ にアクセスします。

  • 式が遅延バインディング プロパティ グループとして、または型が Object または System.Array値として分類されている場合、インデックス式の処理は実行時まで遅延され、インデックス作成は遅延バインドされます。 この式により、遅延バインディング プロパティ アクセスが Objectとして型指定されます。 関連付けられたターゲット式は、ターゲット式 (値の場合) またはプロパティ グループの関連付けられたターゲット式のいずれかです。 実行時に、式は次のように処理されます。

  • 式が遅延バインディング プロパティ グループとして分類されている場合、式はメソッド グループ、プロパティ グループ、または値 (メンバーがインスタンスまたは共有変数の場合) になる可能性があります。 結果がメソッド グループまたはプロパティ グループの場合、オーバーロードの解決がグループに適用され、引数リストの正しいメソッドが決定されます。 オーバーロードの解決に失敗すると、 System.Reflection.AmbiguousMatchException 例外がスローされます。 その後、結果はプロパティ アクセスまたは呼び出しとして処理され、結果が返されます。 呼び出しがサブルーチンの場合、結果は Nothing

  • ターゲット式の実行時の型が配列型または System.Arrayの場合、インデックス式の結果は、指定したインデックス位置にある変数の値になります。

  • それ以外の場合、式の実行時の型には既定のプロパティが必要です。インデックスは、型のすべての既定のプロパティを表すプロパティ グループに対して実行されます。 型に既定のプロパティがない場合は、 System.MissingMemberException 例外がスローされます。

新しい式

New 演算子は、型の新しいインスタンスを作成するために使用されます。 New式には、次の 4 つの形式があります。

  • オブジェクト作成式は、クラス型と値型の新しいインスタンスを作成するために使用されます。

  • 配列作成式は、配列型の新しいインスタンスを作成するために使用されます。

  • デリゲート作成式 (オブジェクト作成式とは異なる構文を持たない) は、デリゲート型の新しいインスタンスを作成するために使用されます。

  • 匿名オブジェクト作成式は、匿名クラス型の新しいインスタンスを作成するために使用されます。

NewExpression
    : ObjectCreationExpression
    | ArrayExpression
    | AnonymousObjectCreationExpression
    ;

New式は値として分類され、結果は型の新しいインスタンスになります。

Object-Creation 式

オブジェクト作成式は、クラス型または構造体型の新しいインスタンスを作成するために使用されます。

ObjectCreationExpression
    : 'New' NonArrayTypeName ( OpenParenthesis ArgumentList? CloseParenthesis )?
      ObjectCreationExpressionInitializer?
    ;

ObjectCreationExpressionInitializer
    : ObjectMemberInitializer
    | ObjectCollectionInitializer
    ;

ObjectMemberInitializer
    : 'With' OpenCurlyBrace FieldInitializerList CloseCurlyBrace
    ;

FieldInitializerList
    : FieldInitializer ( Comma FieldInitializer )*
    ;

FieldInitializer
    : 'Key'? ('.' IdentifierOrKeyword Equals )? Expression
    ;

ObjectCollectionInitializer
    : 'From' CollectionInitializer
    ;

CollectionInitializer
    : OpenCurlyBrace CollectionElementList? CloseCurlyBrace
    ;

CollectionElementList
    : CollectionElement ( Comma CollectionElement )*
    ;

CollectionElement
    : Expression
    | CollectionInitializer
    ;

オブジェクト作成式の型は、クラス型、構造体型、または New 制約を持つ型パラメーターである必要があり、 MustInherit クラスにすることはできません。 Tがクラス型または構造体型で、Aが省略可能な引数リストであるフォーム New T(A)のオブジェクト作成式を指定すると、オーバーロードの解決によって、呼び出すTの正しいコンストラクターが決定されます。 New制約を持つ型パラメーターには、パラメーターなしのコンストラクターが 1 つと見なされます。 呼び出し可能なコンストラクターがない場合は、コンパイル時エラーが発生します。それ以外の場合、式は選択したコンストラクターを使用して T の新しいインスタンスを作成します。 引数がない場合は、かっこを省略できます。

インスタンスが割り当てられる場所は、インスタンスがクラス型か値型かによって異なります。 New クラス型のインスタンスはシステム ヒープ上に作成され、値型の新しいインスタンスはスタック上に直接作成されます。

オブジェクト作成式では、必要に応じて、コンストラクター引数の後にメンバー初期化子の一覧を指定できます。 これらのメンバー初期化子の先頭にはキーワード Withが付けられます。初期化子リストは、 With ステートメントのコンテキストにあるかのように解釈されます。 たとえば、次のクラスを指定します。

Class Customer
    Dim Name As String
    Dim Address As String
End Class

コード:

Module Test
    Sub Main()
        Dim x As New Customer() With { .Name = "Bob Smith", _
            .Address = "123 Main St." }
    End Sub
End Module

次とほぼ同じです。

Module Test
    Sub Main()
        Dim x, _t1 As Customer

        _t1 = New Customer()
        With _t1
            .Name = "Bob Smith"
            .Address = "123 Main St."
        End With

        x = _t1
    End Sub
End Module

各初期化子は、割り当てる名前を指定する必要があります。また、その名前は、構築する型のReadOnly 以外のインスタンス変数またはプロパティである必要があります。構築される型が Objectされている場合、メンバー アクセスは遅延バインドされません。 初期化子は、 Key キーワードを使用できません。 型の各メンバーは、1 回だけ初期化できます。 ただし、初期化子式は相互に参照する場合があります。 例えば次が挙げられます。

Module Test
    Sub Main()
        Dim x As New Customer() With { .Name = "Bob Smith", _
            .Address = .Name & " St." }
    End Sub
End Module

初期化子は左から右に割り当てられるため、初期化子がまだ初期化されていないメンバーを参照している場合は、コンストラクターの実行後にインスタンス変数の値が表示されます。

Module Test
    Sub Main()
        ' The value of Address will be " St." since Name has not been
        ' assigned yet.
        Dim x As New Customer() With { .Address = .Name & " St." }
    End Sub
End Module

初期化子は入れ子にすることができます。

Class Customer
    Dim Name As String
    Dim Address As Address
    Dim Age As Integer
End Class

Class Address
    Dim Street As String
    Dim City As String
    Dim State As String
    Dim ZIP As String
End Class

Module Test
    Sub Main()
        Dim c As New Customer() With { _
            .Name = "John Smith", _
            .Address = New Address() With { _
                .Street = "23 Main St.", _
                .City = "Peoria", _
                .State = "IL", _
                .ZIP = "13934" }, _
            .Age = 34 }
    End Sub
End Module

作成する型がコレクション型で、 Add という名前のインスタンス メソッド (拡張メソッドや共有メソッドを含む) がある場合、オブジェクト作成式では、キーワード Fromでプレフィックスが付いたコレクション初期化子を指定できます。 オブジェクト作成式では、メンバー初期化子とコレクション初期化子の両方を指定できません。 コレクション初期化子の各要素は、 Add 関数の呼び出しに引数として渡されます。 例えば次が挙げられます。

Dim list = New List(Of Integer)() From { 1, 2, 3, 4 }

〜に相当します。

Dim list = New List(Of Integer)()
list.Add(1)
list.Add(2)
list.Add(3)

要素がコレクション初期化子自体の場合、サブコレクション初期化子の各要素は、 Add 関数に個別の引数として渡されます。 たとえば、次のようになります。

Dim dict = Dictionary(Of Integer, String) From { { 1, "One" },{ 2, "Two" } }

〜に相当します。

Dim dict = New Dictionary(Of Integer, String)
dict.Add(1, "One")
dict.Add(2, "Two")

この拡張は常に行われ、1レベルの深さしか行われません。その後、サブ初期化子は配列リテラルと見なされます。 例えば次が挙げられます。

' Error: List(Of T) does not have an Add method that takes two parameters.
Dim list = New List(Of Integer())() From { { 1, 2 }, { 3, 4 } }

' OK, this initializes the dictionary with (Integer, Integer()) pairs.
Dim dict = New Dictionary(Of Integer, Integer())() From _
        { {  1, { 2, 3 } }, { 3, { 4, 5 } } }

配列式

配列式は、配列型の新しいインスタンスを作成するために使用されます。 配列式には、配列作成式と配列リテラルの 2 種類があります。

配列作成式

配列サイズ初期化修飾子が指定されている場合、結果の配列型は、配列サイズ初期化引数リストから個々の引数を削除することによって派生します。 各引数の値によって、新しく割り当てられた配列インスタンス内の対応する次元の上限が決まります。 式に空でないコレクション初期化子がある場合、引数リスト内の各引数は定数である必要があり、式リストで指定されるランクとディメンションの長さはコレクション初期化子のものと一致する必要があります。

Dim a() As Integer = New Integer(2) {}
Dim b() As Integer = New Integer(2) { 1, 2, 3 }
Dim c(,) As Integer = New Integer(1, 2) { { 1, 2, 3 } , { 4, 5, 6 } }

' Error, length/initializer mismatch.
Dim d() As Integer = New Integer(2) { 0, 1, 2, 3 }

配列サイズ初期化修飾子が指定されていない場合、型名は配列型でなければならず、コレクション初期化子は空であるか、指定された配列型のランクと同じレベルの入れ子になっている必要があります。 最も内側の入れ子レベルのすべての要素は、配列の要素型に暗黙的に変換でき、値として分類する必要があります。 入れ子になった各コレクション初期化子の要素の数は、常に同じレベルの他のコレクションのサイズと一致している必要があります。 個々の次元の長さは、コレクション初期化子の対応する入れ子レベルの要素の数から推論されます。 コレクション初期化子が空の場合、各ディメンションの長さは 0 です。

Dim e() As Integer = New Integer() { 1, 2, 3 }
Dim f(,) As Integer = New Integer(,) { { 1, 2, 3 } , { 4, 5, 6 } }

' Error: Inconsistent numbers of elements!
Dim g(,) As Integer = New Integer(,) { { 1, 2 }, { 4, 5, 6 } }

' Error: Inconsistent levels of nesting!
Dim h(,) As Integer = New Integer(,) { 1, 2, { 3, 4 } }

コレクション初期化子の最も外側の入れ子レベルは配列の左端の次元に対応し、最も内側の入れ子レベルは右端の次元に対応します。 例:

Dim array As Integer(,) = _
    { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }, { 8, 9 } }

次と同じです。

Dim array(4, 1) As Integer

array(0, 0) = 0: array(0, 1) = 1
array(1, 0) = 2: array(1, 1) = 3
array(2, 0) = 4: array(2, 1) = 5
array(3, 0) = 6: array(3, 1) = 7
array(4, 0) = 8: array(4, 1) = 9

コレクション初期化子が空の場合 (つまり、中かっこを含むが初期化子リストを含まないもの)、初期化される配列の次元の境界がわかっている場合、空のコレクション初期化子は、すべての要素が要素型の既定値に初期化された、指定したサイズの配列インスタンスを表します。 初期化される配列の次元の境界が不明な場合、空のコレクション初期化子は、すべての次元がサイズ 0 である配列インスタンスを表します。

配列インスタンスのランクと各ディメンションの長さは、インスタンスの有効期間全体で一定です。 つまり、既存の配列インスタンスのランクを変更することも、その次元のサイズを変更することもできません。

配列リテラル

配列リテラルは、式コンテキストとコレクション初期化子の組み合わせから要素の型、ランク、および境界が推論される配列を表します。 これについては、セクション 式の再分類で説明します。

ArrayExpression
    : ArrayCreationExpression
    | ArrayLiteralExpression
    ;

ArrayCreationExpression
    : 'New' NonArrayTypeName ArrayNameModifier CollectionInitializer
    ;

ArrayLiteralExpression
    : CollectionInitializer
    ;

例えば次が挙げられます。

' array of integers
Dim a = {1, 2, 3}

' array of shorts
Dim b = {1S, 2S, 3S}

' array of shorts whose type is taken from the context
Dim c As Short() = {1, 2, 3}

' array of type Integer(,)
Dim d = {{1, 0}, {0, 1}}

' jagged array of rank ()()
Dim e = {({1, 0}), ({0, 1})}

' error: inconsistent rank
Dim f = {{1}, {2, 3}}

' error: inconsistent rank
Dim g = {1, {2}}

配列リテラル内のコレクション初期化子の形式と要件は、配列作成式のコレクション初期化子の場合とまったく同じです。

"注: 配列リテラルは、それ自体に配列を作成しません。代わりに、式を値に再分類して配列を作成します。 たとえば、Integer()からShort()への変換がないため、変換CType(new Integer() {1,2,3}, Short())できませんが、最初に配列リテラルを配列作成式New Short() {1,2,3}に再分類するため、式CType({1,2,3},Short())が可能です。

Delegate-Creation 式

デリゲート作成式は、デリゲート型の新しいインスタンスを作成するために使用されます。 デリゲート作成式の引数は、メソッド ポインターまたはラムダ メソッドとして分類される式である必要があります。

引数がメソッド ポインターの場合、メソッド ポインターによって参照されるメソッドの 1 つがデリゲート型のシグネチャに適用できる必要があります。 Mメソッドは、次の場合にDデリゲート型に適用できます。

  • MPartial されていないか、本文を持っています。

  • MDの両方が関数であるか、Dがサブルーチンです。

  • MD は同じ数のパラメーターを持っています。

  • Mのパラメーター型はそれぞれ、Dの対応するパラメーター型の型からの変換を持ち、その修飾子 (ByRefByVal) が一致します。

  • Mの戻り値の型 (存在する場合) は、Dの戻り値の型に変換されます。

メソッド ポインターが遅延バインディング アクセスを参照する場合、遅延バインディング アクセスはデリゲート型と同じ数のパラメーターを持つ関数に対するものと見なされます。

厳密なセマンティクスが使用されておらず、メソッド ポインターによって参照されるメソッドが 1 つしかないが、パラメーターがなくデリゲート型によって参照されるため適用できない場合、メソッドは適用可能と見なされ、パラメーターまたは戻り値は単に無視されます。 例えば次が挙げられます。

Delegate Sub F(x As Integer)

Module Test
    Sub M()
    End Sub

    Sub Main()
        ' Valid
        Dim x As F = AddressOf M
    End Sub
End Module

"注: この緩和は、拡張メソッドのために厳密なセマンティクスが使用されていない場合にのみ許可されます。 拡張メソッドは通常のメソッドが適用できない場合にのみ考慮されるため、パラメーターのないインスタンス メソッドでは、デリゲートの構築を目的として、パラメーターを持つ拡張メソッドを非表示にすることができます。

メソッド ポインターによって参照される複数のメソッドがデリゲート型に適用できる場合は、オーバーロード解決を使用して候補メソッド間を選択します。 デリゲートのパラメーターの型は、オーバーロード解決の目的で引数の型として使用されます。 最も適切なメソッド候補が 1 つもない場合は、コンパイル時エラーが発生します。 次の例では、2 番目の Square メソッドを参照するデリゲートを使用してローカル変数が初期化されます。これは、そのメソッドが DoubleFuncのシグネチャと戻り値の型に適用できるためです。

Delegate Function DoubleFunc(x As Double) As Double

Module Test
    Function Square(x As Single) As Single
        Return x * x
    End Function 

    Function Square(x As Double) As Double
        Return x * x
    End Function

    Sub Main()
        Dim a As New DoubleFunc(AddressOf Square)
    End Sub
End Module

2 番目の Square メソッドが存在しない場合は、最初の Square メソッドが選択されます。 コンパイル環境または Option Strictによって厳密なセマンティクスが指定されている場合、メソッド ポインターによって参照される最も具体的なメソッドがデリゲート シグネチャよりも狭い場合、コンパイル時エラーが発生します。 メソッド M は、次の場合に D デリゲート型よりも狭いと見なされます。

  • Mのパラメーター型には、Dの対応するパラメーター型への拡大変換があります。

  • または、戻り値の型がある場合、 M の戻り値の型は、 Dの戻り値の型に縮小変換されます。

型引数がメソッド ポインターに関連付けられている場合は、同じ数の型引数を持つメソッドのみが考慮されます。 メソッド ポインターに関連付けられている型引数がない場合は、ジェネリック メソッドに対してシグネチャを照合するときに型推論が使用されます。 他の通常の型推論とは異なり、デリゲートの戻り値の型は型引数を推論するときに使用されますが、ジェネリックオーバーロードが最も少ない場合でも戻り値の型は考慮されません。 次の例は、デリゲート作成式に型引数を指定する両方の方法を示しています。

Delegate Function D(s As String, i As Integer) As Integer
Delegate Function E() As Integer

Module Test
    Public Function F(Of T)(s As String, t1 As T) As T
    End Function

    Public Function G(Of T)() As T
    End Function

    Sub Main()
        Dim d1 As D = AddressOf f(Of Integer)    ' OK, type arg explicit
        Dim d2 As D = AddressOf f                ' OK, type arg inferred

        Dim e1 As E = AddressOf g(Of Integer)    ' OK, type arg explicit
        Dim e2 As E = AddressOf g                ' OK, infer from return
  End Sub
End Module

上記の例では、ジェネリック メソッドを使用して非ジェネリック デリゲート型がインスタンス化されました。 ジェネリック メソッドを使用して、構築されたデリゲート型のインスタンスを作成することもできます。 例えば次が挙げられます。

Delegate Function Predicate(Of U)(u1 As U, u2 As U) As Boolean

Module Test
    Function Compare(Of T)(t1 As List(of T), t2 As List(of T)) As Boolean
        ...
    End Function

    Sub Main()
        Dim p As Predicate(Of List(Of Integer))
        p = AddressOf Compare(Of Integer)
    End Sub
End Module

デリゲート作成式の引数がラムダ メソッドの場合、ラムダ メソッドはデリゲート型のシグネチャに適用できる必要があります。 ラムダ メソッド L は、次の場合に D デリゲート型に適用できます。

  • Lにパラメーターがある場合、Dは同じ数のパラメーターを持っています。 ( L にパラメーターがない場合、 D のパラメーターは無視されます)。

  • Lのパラメーター型はそれぞれ、Dの対応するパラメーター型の型に変換され、その修飾子 (ByRefByVal) が一致します。

  • Dが関数の場合、Lの戻り値の型はDの戻り値の型に変換されます。 ( D がサブルーチンの場合、 L の戻り値は無視されます)。

Lのパラメーターのパラメーター型を省略すると、Dの対応するパラメーターの型が推論されます。Lのパラメーターに配列または null 許容名修飾子がある場合、コンパイル時エラーが発生します。 Lのすべてのパラメーター型が使用可能になると、ラムダ メソッド内の式の型が推論されます。 例えば次が挙げられます。

Delegate Function F(x As Integer, y As Long) As Long

Module Test
    Sub Main()
        ' b inferred to Integer, c and return type inferred to Long
        Dim a As F = Function(b, c) b + c

        ' e and return type inferred to Integer, f inferred to Long
        Dim d As F = Function(e, f) e + CInt(f)
    End Sub
End Module

デリゲートシグネチャがラムダメソッドまたはメソッドシグネチャと正確に一致しない状況では、.NET Framework がデリゲートの作成をネイティブにサポートしていない場合があります。 このような状況では、ラムダ メソッド式が 2 つのメソッドに一致するために使用されます。 例えば次が挙げられます。

Delegate Function IntFunc(x As Integer) As Integer

Module Test
    Function SquareString(x As String) As String
        Return CInt(x) * CInt(x)
    End Function 

    Sub Main()
        ' The following two lines are equivalent
        Dim a As New IntFunc(AddressOf SquareString)
        Dim b As New IntFunc( _
            Function(x As Integer) CInt(SquareString(CStr(x))))
    End Sub
End Module

デリゲート作成式の結果は、メソッド ポインター式から関連付けられたターゲット式 (存在する場合) と一致するメソッドを参照するデリゲート インスタンスです。 ターゲット式が値型として型指定されている場合、デリゲートはヒープ上のオブジェクトのメソッドのみを指すことができるため、値型がシステム ヒープにコピーされます。 デリゲートが参照するメソッドとオブジェクトは、デリゲートの有効期間全体にわたって一定のままです。 つまり、デリゲートの作成後に、デリゲートのターゲットまたはオブジェクトを変更することはできません。

匿名 Object-Creation 式

メンバー初期化子を持つオブジェクト作成式では、型名を完全に省略することもできます。

AnonymousObjectCreationExpression
    : 'New' ObjectMemberInitializer
    ;

その場合、匿名型は、式の一部として初期化されたメンバーの型と名前に基づいて構築されます。 例えば次が挙げられます。

Module Test
    Sub Main()
        Dim Customer = New With { .Name = "John Smith", .Age = 34 }

        Console.WriteLine(Customer.Name)
    End Sub
End Module

匿名オブジェクト作成式によって作成される型は、名前を持たないクラスであり、 Objectから直接継承され、メンバー初期化子リストで割り当てられたメンバーと同じ名前のプロパティのセットを持ちます。 各プロパティの型は、ローカル変数の型推論と同じ規則を使用して推論されます。 また、生成された匿名型は ToStringをオーバーライドし、すべてのメンバーとその値の文字列表現を返します。 (この文字列の正確な形式は、この仕様の範囲外です)。

既定では、匿名型によって生成されるプロパティは読み取り/書き込みです。 匿名型プロパティを読み取り専用としてマークするには、 Key 修飾子を使用します。 Key修飾子は、匿名型が表す値を一意に識別するためにフィールドを使用できることを指定します。 プロパティを読み取り専用にするだけでなく、匿名型が EqualsGetHashCode をオーバーライドし、インターフェイス System.IEquatable(Of T) を実装します ( Tの匿名型を入力します)。 メンバーは次のように定義されます。

Function Equals(obj As Object) As Boolean Function Equals(val As T) As Booleanは、2 つのインスタンスが同じ型であることを検証し、Object.Equalsを使用して各Keyメンバーを比較することによって実装されます。 すべてのKeyメンバーが等しい場合、EqualsTrueを返し、それ以外の場合はEqualsFalseを返します。

Function GetHashCode() As Integer は、匿名型の 2 つのインスタンスに対して Equals が true の場合、 GetHashCode は同じ値を返すように実装されます。 ハッシュはシード値で始まり、その後、各Keyメンバーについてハッシュに 31 を乗算し、メンバーが参照型ではない場合、または Nothing の値を持つ null 許容値型の場合は、Key メンバーのハッシュ値 (GetHashCode によって提供) を追加します。

たとえば、ステートメントで作成された型は次のようになります。

Dim zipState = New With { Key .ZipCode = 98112, .State = "WA" }

は、ほぼ次のようなクラスを作成します (正確な実装は異なる場合があります)。

Friend NotInheritable Class $Anonymous1
    Implements IEquatable(Of $Anonymous1)

    Private ReadOnly _zipCode As Integer
    Private _state As String

    Public Sub New(zipCode As Integer, state As String)
        _zipCode = zipcode
        _state = state
    End Sub

    Public ReadOnly Property ZipCode As Integer
        Get
            Return _zipCode
        End Get
    End Property

    Public Property State As String
        Get
            Return _state
        End Get
        Set (value As Integer)
            _state = value
        End Set
    End Property

    Public Overrides Function Equals(obj As Object) As Boolean
        Dim val As $Anonymous1 = TryCast(obj, $Anonymous1)
        Return Equals(val)
    End Function

    Public Overloads Function Equals(val As $Anonymous1) As Boolean _
        Implements IEquatable(Of $Anonymous1).Equals

        If val Is Nothing Then 
            Return False
        End If

        If Not Object.Equals(_zipCode, val._zipCode) Then 
            Return False
        End If

        Return True
    End Function

    Public Overrides Function GetHashCode() As Integer
        Dim hash As Integer = 0

        hash = hash Xor _zipCode.GetHashCode()

        Return hash
    End Function

    Public Overrides Function ToString() As String
        Return "{ Key .ZipCode = " & _zipCode & ", .State = " & _state & " }"
    End Function
End Class

匿名型が別の型のフィールドから作成される状況を簡略化するために、次の場合に式からフィールド名を直接推論できます。

  • 単純な名前式 x 名前 xを推論します。

  • メンバー アクセス式 x.y は、名前 yを推論します。

  • 名前yを推論x!yディクショナリ参照式。

  • 名前xを推論x()引数のない呼び出しまたはインデックス式。

  • の名前を推論、XML メンバー アクセス式。

  • z名を推論x.<y>.zメンバー アクセス式のターゲットである XML メンバー アクセス式。

  • 名前zを推論x.<y>.z()引数のない呼び出しまたはインデックス式のターゲットである XML メンバー アクセス式。

  • 名前yを推論x.<y>(0)呼び出しまたはインデックス式のターゲットである XML メンバー アクセス式。

初期化子は、推論された名前に対する式の代入として解釈されます。 たとえば、次の初期化子は同等です。

Class Address
    Public Street As String
    Public City As String
    Public State As String
    Public ZIP As String
End Class

Class C1
    Sub Test(a As Address)
        Dim cityState1 = New With { .City = a.City, .State = a.State }
        Dim cityState2 = New With { a.City, a.State }
    End Sub
End Class

GetHashCodeなど、型の既存のメンバーと競合するメンバー名が推論されると、コンパイル時エラーが発生します。 通常のメンバー初期化子とは異なり、匿名オブジェクト作成式では、メンバー初期化子が循環参照を持ったり、初期化前にメンバーを参照したりすることはできません。 例えば次が挙げられます。

Module Test
    Sub Main()
        ' Error: Circular references
        Dim x = New With { .a = .b, .b = .a }

        ' Error: Referring to .b before it has been assigned to
        Dim y = New With { .a = .b, .b = 10 }

        ' Error: Referring to .a before it has been assigned to
        Dim z = New With { .a = .a }
    End Sub
End Module

同じメソッド内で 2 つの匿名クラス作成式が発生し、結果として同じ図形が生成された場合 、プロパティの順序、プロパティ名、およびプロパティ型がすべて一致する場合、両方とも同じ匿名クラスを参照します。 初期化子を持つインスタンスまたは共有メンバー変数のメソッド スコープは、変数が初期化されるコンストラクターです。

"注: コンパイラは、アセンブリ レベルなど、匿名型をさらに統合することを選択できますが、現時点では依存できません。

キャスト式

キャスト式は、特定の型に対して式を強制します。 特定のキャスト キーワードは、式をプリミティブ型に強制します。 CTypeTryCastDirectCastの 3 つの一般的なキャスト キーワードは、式を型に強制します。

CastExpression
    : 'DirectCast' OpenParenthesis Expression Comma TypeName CloseParenthesis
    | 'TryCast' OpenParenthesis Expression Comma TypeName CloseParenthesis
    | 'CType' OpenParenthesis Expression Comma TypeName CloseParenthesis
    | CastTarget OpenParenthesis Expression CloseParenthesis
    ;

CastTarget
    : 'CBool' | 'CByte' | 'CChar'  | 'CDate'  | 'CDec' | 'CDbl' | 'CInt'
    | 'CLng'  | 'CObj'  | 'CSByte' | 'CShort' | 'CSng' | 'CStr' | 'CUInt'
    | 'CULng' | 'CUShort'
    ;

DirectCastTryCast には特別な動作があります。 このため、ネイティブ変換のみがサポートされます。 さらに、 TryCast 式のターゲット型を値型にすることはできません。 ユーザー定義の変換演算子は、 DirectCast または TryCast を使用する場合は考慮されません。 (注。DirectCastおよびTryCastサポートされる変換セットは、"ネイティブ CLR" 変換を実装するため制限されます。DirectCastの目的は、"unbox" 命令の機能を提供することですが、TryCastの目的は "isinst" 命令の機能を提供することです。CLR 命令にマップされるため、CLR で直接サポートされていない変換をサポートすると、意図した目的が無効になります)。

DirectCast は、 Object として型指定された式を CTypeとは異なる方法で変換します。 ランタイム型がプリミティブ値型であるObject型の式を変換する場合、指定した型が式の実行時型と同じでない場合はDirectCastSystem.InvalidCastException例外をスローし、式がNothingに評価される場合はSystem.NullReferenceExceptionをスローします。 (注。 前述のように、 DirectCast 式の型が Objectされると、CLR 命令 "unbox" に直接マップされます。これに対し、 CType は、プリミティブ型間の変換をサポートできるように、変換を実行するランタイム ヘルパーの呼び出しに変わります。 Object 式がプリミティブ値型に変換され、実際のインスタンスの型がターゲット型と一致する場合、 DirectCastCTypeよりも大幅に高速になります)。

TryCast は式を変換しますが、式をターゲット型に変換できない場合は例外をスローしません。 代わりに、式を実行時に変換できない場合、 TryCastNothing になります。 (注。 前述のように、 TryCast は CLR 命令 "isinst" に直接マップされます。型チェックと変換を 1 つの操作に組み合わせることにより、 TryCastTypeOf ... Is を実行してから CTypeを行うよりも安くなる可能性があります)。

例えば次が挙げられます。

Interface ITest
    Sub Test()
End Interface

Module Test
    Sub Convert(o As Object)
        Dim i As ITest = TryCast(o, ITest)

        If i IsNot Nothing Then
            i.Test()
        End If
    End Sub
End Module

式の型から指定した型への変換が存在しない場合は、コンパイル時エラーが発生します。 それ以外の場合、式は値として分類され、結果は変換によって生成される値になります。

演算子式

演算子には 2 種類あります。 単項演算子 は 1 つのオペランドを受け取り、プレフィックス表記 (たとえば、 -x) を使用します。 二項演算子 は、2 つのオペランドを受け取り、インフィックス表記 (たとえば、 x + y) を使用します。 常に Booleanになる関係演算子を除き、特定の型に対して定義された演算子は、その型になります。 演算子のオペランドは常に値として分類する必要があります。演算子式の結果は値として分類されます。

OperatorExpression
    : ArithmeticOperatorExpression
    | RelationalOperatorExpression
    | LikeOperatorExpression
    | ConcatenationOperatorExpression
    | ShortCircuitLogicalOperatorExpression
    | LogicalOperatorExpression
    | ShiftOperatorExpression
    | AwaitOperatorExpression
    ;

演算子の優先順位と結合規則

式に複数の二項演算子が含まれている場合、演算子の 優先順位 によって、個々の二項演算子の評価順序が制御されます。 たとえば、*演算子の方が+演算子よりも優先順位が高いため、式x + y * zx + (y * z)として評価されます。 次の表に、優先順位の降順で二項演算子を示します。

カテゴリ 演算子
プライマリ すべての非演算子式
待つ Await
累乗 ^
単項否定 +-
乗法 */
整数の除算 \
モジュラス Mod
加法 +-
連結 &
シフト <<>>
リレーショナル =<><><=>=LikeIsIsNot
論理 NOT Not
論理積 AndAndAlso
論理和 OrOrElse
論理 XOR Xor

式に同じ優先順位を持つ 2 つの演算子が含まれている場合、演算子の 結合規則 によって、操作の実行順序が制御されます。 すべての二項演算子は左連想であり、操作は左から右に実行されます。 優先順位と結合規則は、かっこで囲まれた式を使用して制御できます。

オブジェクト オペランド

各演算子でサポートされる標準型に加えて、すべての演算子は型 Objectのオペランドをサポートします。 Objectオペランドに適用される演算子は、Object値に対して行われたメソッド呼び出しと同様に処理されます。遅延バインディング メソッド呼び出しが選択される可能性があります。この場合、コンパイル時の型ではなく、オペランドの実行時の型によって演算の有効性と型が決定されます。 コンパイル環境または Option Strictによって厳密なセマンティクスが指定されている場合、 Object 型のオペランドを持つ演算子は、 TypeOf...IsIs 、および IsNot 演算子を除き、コンパイル時エラーを引き起こします。

演算子の解決で、操作を遅延バインディングで実行する必要があると判断された場合、オペランドの実行時の型が演算子でサポートされている型である場合、演算の結果はオペランド型に演算子を適用した結果になります。 Nothing値は、二項演算子式のもう一方のオペランドの型の既定値として扱われます。 単項演算子式の場合、または両方のオペランドが 2 項演算子式で Nothing されている場合、演算子の型は Integer されるか、演算子の唯一の結果型になります (演算子が Integerされない場合)。 操作の結果は常に Objectにキャストされます。 オペランド型に有効な演算子がない場合は、 System.InvalidCastException 例外がスローされます。 実行時の変換は、暗黙的か明示的かに関係なく行われます。

数値バイナリ演算の結果でオーバーフロー例外が発生する場合 (整数オーバーフロー チェックがオンかオフかに関係なく)、可能であれば、結果の型は次の大きい数値型に昇格されます。 たとえば、次のコードを考えてみましょう。

Module Test
    Sub Main()
        Dim o As Object = CObj(CByte(2)) * CObj(CByte(255))

        Console.WriteLine(o.GetType().ToString() & " = " & o)
    End Sub
End Module

次の結果が出力されます。

System.Int16 = 512

数値を保持するために使用できる数値型が広い場合は、 System.OverflowException 例外がスローされます。

演算子の解決

演算子の型とオペランドのセットを指定すると、演算子の解決によって、オペランドに使用する演算子が決まります。 演算子を解決する場合は、次の手順を使用して、ユーザー定義演算子が最初に考慮されます。

  1. まず、すべての候補演算子が収集されます。 候補演算子は、ソース型の特定の演算子型のすべてのユーザー定義演算子と、ターゲット型の特定の型のすべてのユーザー定義演算子です。 ソースの種類と変換先の型が関連付けられている場合、一般的な演算子は 1 回だけ考慮されます。

  2. 次に、オーバーロードの解決が演算子とオペランドに適用され、最も具体的な演算子が選択されます。 二項演算子の場合、遅延バインディング呼び出しが発生する可能性があります。

T?の候補演算子を収集する場合は、代わりに T 型の演算子が使用されます。 null 非許容値型のみを含む Tのユーザー定義演算子も、いずれもリフトされます。 リフトされた演算子は、 IsTrueIsFalse の戻り値の型 ( Booleanする必要があります) を除き、任意の値型の null 許容バージョンを使用します。 リフトされた演算子は、オペランドを null 非許容バージョンに変換し、ユーザー定義演算子を評価してから、結果の型を null 許容バージョンに変換することによって評価されます。 ether オペランドが Nothing場合、式の結果は、結果型の null 許容バージョンとして型指定 Nothing 値になります。 例えば次が挙げられます。

Structure T
    ...
End Structure

Structure S
    Public Shared Operator +(ByVal op1 As S, ByVal op2 As T) As T
        ...
    End Operator
End Structure

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

        ' Valid, as S + T = T is lifted to S? + T? = T?
        z = x + y 
    End Sub
End Module

演算子が 2 項演算子で、オペランドの 1 つが参照型の場合、演算子もリフトされますが、演算子へのバインディングではエラーが発生します。 例えば次が挙げられます。

Structure S1
    Public F1 As Integer

    Public Shared Operator +(left As S1, right As String) As S1
       ...
    End Operator
End Structure

Module Test
    Sub Main()
        Dim a? As S1
        Dim s As String
        
        ' Error: '+' is not defined for S1? and String
        a = a + s
    End Sub
End Module

"注: この規則は、将来のバージョンで null 伝達参照型を追加するかどうかが考慮されているために存在します。この場合、2 つの型間の二項演算子の場合の動作が変わります。

変換と同様に、ユーザー定義演算子は、リフトされた演算子よりも常に優先されます。

オーバーロードされた演算子を解決するときに、Visual Basic で定義されているクラスと他の言語で定義されているクラスの間に違いがある可能性があります。

  • 他の言語では、論理演算子とビット演算子の両方として、 NotAnd、および Or がオーバーロードされる場合があります。 外部アセンブリからインポートすると、どちらのフォームもこれらの演算子の有効なオーバーロードとして受け入れられます。 ただし、論理演算子とビット演算子の両方を定義する型では、ビットごとの実装のみが考慮されます。

  • 他の言語では、 >><< は、符号付き演算子と符号なし演算子の両方としてオーバーロードされる場合があります。 外部アセンブリからインポートすると、どちらのフォームも有効なオーバーロードとして受け入れられます。 ただし、符号付き演算子と符号なし演算子の両方を定義する型の場合、符号付き実装のみが考慮されます。

  • オペランドに最も固有のユーザー定義演算子がない場合は、組み込み演算子が考慮されます。 オペランドに組み込み演算子が定義されておらず、いずれかのオペランドに Object 型がある場合、演算子は遅延バインディングで解決されます。それ以外の場合は、コンパイル時エラーが発生します。

以前のバージョンの Visual Basic では、Object 型のオペランドが 1 つだけあり、適用可能なユーザー定義演算子がなく、適用可能な組み込み演算子がない場合は、エラーでした。 Visual Basic 11 の時点で、遅延バインドが解決されるようになりました。 例えば次が挙げられます。

Module Module1
  Sub Main()
      Dim p As Object = Nothing
      Dim U As New Uri("http://www.microsoft.com")
      Dim j = U * p  ' is now resolved late-bound
   End Sub
End Module

組み込み演算子を持つ型 T は、 T?の同じ演算子も定義します。 T?の演算子の結果は、Tの場合と同じになりますが、どちらかのオペランドがNothingの場合、演算子の結果はNothingされます (つまり、null 値が伝達されます)。 演算の型を解決するために、 ? はオペランドを持つすべてのオペランドから削除され、演算の型が決定され、オペランドのいずれかが null 許容値型の場合は ? が演算の型に追加されます。 例えば次が挙げられます。

Dim v1? As Integer = 10
Dim v2 As Long = 20

' Type of operation will be Long?
Console.WriteLine(v1 + v2)

各演算子は、定義されている組み込み型と、オペランド型を指定して実行される演算の型を一覧表示します。 組み込み操作の型の結果は、次の一般的な規則に従います。

  • すべてのオペランドが同じ型で、その型に対して演算子が定義されている場合、変換は行われず、その型の演算子が使用されます。

  • 演算子に対して型が定義されていないオペランドは、次の手順を使用して変換され、演算子は新しい型に対して解決されます。

    • オペランドは、演算子とオペランドの両方に対して定義され、暗黙的に変換可能な次の最も広い型に変換されます。

    • そのような型がない場合、オペランドは、演算子とオペランドの両方に対して定義され、暗黙的に変換可能な次の最も狭い型に変換されます。

    • このような型がない場合、または変換が行えない場合は、コンパイル時エラーが発生します。

  • それ以外の場合、オペランドはより広いオペランド型に変換され、その型の演算子が使用されます。 より狭いオペランド型をより広い演算子型に暗黙的に変換できない場合は、コンパイル時エラーが発生します。

ただし、これらの一般的な規則にもかかわらず、演算子の結果テーブルにはいくつかの特殊なケースが呼び出されています。

"注: 書式設定の理由から、演算子の型テーブルでは、定義済みの名前が最初の 2 文字に省略されます。 したがって、"By" は Byte、"UI" は UInteger、"St" は Stringなどです。"Err" は、指定されたオペランド型に対して定義された演算がないことを意味します。

算術演算子

*/\^Mod+-の演算子は算術演算子です。

ArithmeticOperatorExpression
    : UnaryPlusExpression
    | UnaryMinusExpression
    | AdditionOperatorExpression
    | SubtractionOperatorExpression
    | MultiplicationOperatorExpression
    | DivisionOperatorExpression
    | ModuloOperatorExpression
    | ExponentOperatorExpression
    ;

浮動小数点演算は、演算の結果の型よりも高い精度で実行できます。 たとえば、一部のハードウェア アーキテクチャでは、 Double 型よりも範囲と精度が高い "extended" 浮動小数点型または "long double" 浮動小数点型がサポートされ、この高精度型を使用してすべての浮動小数点演算が暗黙的に実行されます。 ハードウェア アーキテクチャは、パフォーマンスの過剰なコストでのみ、精度の低い浮動小数点演算を実行するために作成できます。Visual Basic では、パフォーマンスと精度の両方を失う実装を必要とするのではなく、すべての浮動小数点演算に高い精度の型を使用できます。 より正確な結果をもたらす以外には、測定可能な効果はほとんどありません。 ただし、 x * y / z形式の式では、乗算によって Double 範囲外の結果が生成されますが、後続の除算では一時的な結果が Double の範囲に戻ります。式が高い範囲の形式で評価されると、無限大ではなく有限の結果が生成される可能性があります。

単項プラス演算子

UnaryPlusExpression
    : '+' Expression
    ;

単項プラス演算子は、 ByteSByteUShortShortUIntegerIntegerULongLongSingleDouble、および Decimal の型に対して定義されます。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
Sh エスビー によって Sh アメリカ UI Lo UL規格 De Si する エラー エラー する Ob

単項マイナス演算子

UnaryMinusExpression
    : '-' Expression
    ;

単項マイナス演算子は、次の型に対して定義されます。

SByteShortIntegerLong。 結果は、オペランドを 0 から減算することによって計算されます。 整数オーバーフロー 検査がオンで、オペランドの値が負の最大 SByteShortInteger、または Longである場合、 System.OverflowException 例外がスローされます。 それ以外の場合、オペランドの値が負の最大 SByteShortInteger、または Longの場合、結果はその同じ値になり、オーバーフローは報告されません。

SingleDouble. 結果は、値 0 と Infinity を含め、符号が反転されたオペランドの値になります。 オペランドが NaN の場合、結果も NaN になります。

Decimal。 結果は、オペランドを 0 から減算することによって計算されます。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
Sh エスビー Sh Sh Lo Lo De De Si する エラー エラー する Ob

加算演算子

加算演算子は、2 つのオペランドの合計を計算します。

AdditionOperatorExpression
    : Expression '+' LineTerminator? Expression
    ;

加算演算子は、次の型に対して定義されます。

  • ByteSByteUShortShortUIntegerIntegerULong、および Long。 整数オーバーフロー チェックがオンで、合計が結果の型の範囲外の場合は、 System.OverflowException 例外がスローされます。 それ以外の場合、オーバーフローは報告されず、結果の重要な上位ビットは破棄されます。

  • SingleDouble. 合計は、IEEE 754 算術の規則に従って計算されます。

  • Decimal。 結果の値が 10 進形式で表すには大きすぎる場合は、 System.OverflowException 例外がスローされます。 結果の値が小さすぎて 10 進形式で表すと、結果は 0 になります。

  • String。 2 つの String オペランドが連結されます。

  • DateSystem.DateTime型は、オーバーロードされた加算演算子を定義します。 System.DateTimeは組み込みのDate型と同等であるため、これらの演算子はDate型でも使用できます。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー Sh エスビー Sh Sh Lo Lo De De Si する エラー エラー する Ob
SB エスビー Sh Sh Lo Lo De De Si する エラー エラー する Ob
単位 によって Sh アメリカ UI Lo UL規格 De Si する エラー エラー する Ob
Sh Sh Lo Lo De De Si する エラー エラー する Ob
米国 アメリカ UI Lo UL規格 De Si する エラー エラー する Ob
Lo Lo De De Si する エラー エラー する Ob
UI UI Lo UL規格 De Si する エラー エラー する Ob
Lo Lo De De Si する エラー エラー する Ob
UL UL規格 De Si する エラー エラー する Ob
De De Si する エラー エラー する Ob
Si Si する エラー エラー する Ob
すべきこと する エラー エラー する Ob
Da エラー Ob
Ch Ob
Ob
Ob Ob

減算演算子

減算演算子は、最初のオペランドから 2 番目のオペランドを減算します。

SubtractionOperatorExpression
    : Expression '-' LineTerminator? Expression
    ;

減算演算子は、次の型に対して定義されます。

  • ByteSByteUShortShortUIntegerIntegerULong、および Long。 整数オーバーフロー チェックがオンで、その差が結果の型の範囲外である場合は、 System.OverflowException 例外がスローされます。 それ以外の場合、オーバーフローは報告されず、結果の重要な上位ビットは破棄されます。

  • SingleDouble. この違いは、IEEE 754 算術の規則に従って計算されます。

  • Decimal。 結果の値が 10 進形式で表すには大きすぎる場合は、 System.OverflowException 例外がスローされます。 結果の値が小さすぎて 10 進形式で表すと、結果は 0 になります。

  • DateSystem.DateTime型は、オーバーロードされた減算演算子を定義します。 System.DateTimeは組み込みのDate型と同等であるため、これらの演算子はDate型でも使用できます。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー Sh エスビー Sh Sh Lo Lo De De Si する エラー エラー する Ob
SB エスビー Sh Sh Lo Lo De De Si する エラー エラー する Ob
単位 によって Sh アメリカ UI Lo UL規格 De Si する エラー エラー する Ob
Sh Sh Lo Lo De De Si する エラー エラー する Ob
米国 アメリカ UI Lo UL規格 De Si する エラー エラー する Ob
Lo Lo De De Si する エラー エラー する Ob
UI UI Lo UL規格 De Si する エラー エラー する Ob
Lo Lo De De Si する エラー エラー する Ob
UL UL規格 De Si する エラー エラー する Ob
De De Si する エラー エラー する Ob
Si Si する エラー エラー する Ob
すべきこと する エラー エラー する Ob
Da エラー エラー エラー エラー
Ch エラー エラー エラー
する Ob
Ob Ob

乗算演算子

乗算演算子は、2 つのオペランドの積を計算します。

MultiplicationOperatorExpression
    : Expression '*' LineTerminator? Expression
    ;

乗算演算子は、次の型に対して定義されます。

  • ByteSByteUShortShortUIntegerIntegerULong、および Long。 整数オーバーフロー チェックがオンで、製品が結果の型の範囲外である場合は、 System.OverflowException 例外がスローされます。 それ以外の場合、オーバーフローは報告されず、結果の重要な上位ビットは破棄されます。

  • SingleDouble. この積は、IEEE 754 算術の規則に従って計算されます。

  • Decimal。 結果の値が 10 進形式で表すには大きすぎる場合は、 System.OverflowException 例外がスローされます。 結果の値が小さすぎて 10 進形式で表すと、結果は 0 になります。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー Sh エスビー Sh Sh Lo Lo De De Si する エラー エラー する Ob
SB エスビー Sh Sh Lo Lo De De Si する エラー エラー する Ob
単位 によって Sh アメリカ UI Lo UL規格 De Si する エラー エラー する Ob
Sh Sh Lo Lo De De Si する エラー エラー する Ob
米国 アメリカ UI Lo UL規格 De Si する エラー エラー する Ob
Lo Lo De De Si する エラー エラー する Ob
UI UI Lo UL規格 De Si する エラー エラー する Ob
Lo Lo De De Si する エラー エラー する Ob
UL UL規格 De Si する エラー エラー する Ob
De De Si する エラー エラー する Ob
Si Si する エラー エラー する Ob
すべきこと する エラー エラー する Ob
Da エラー エラー エラー エラー
Ch エラー エラー エラー
する Ob
Ob Ob

除算演算子

除算演算子は、2 つのオペランドの商を計算します。 除算演算子には、標準 (浮動小数点) 除算演算子と整数除算演算子の 2 つがあります。

DivisionOperatorExpression
    : FPDivisionOperatorExpression
    | IntegerDivisionOperatorExpression
    ;

FPDivisionOperatorExpression
    : Expression '/' LineTerminator? Expression
    ;

IntegerDivisionOperatorExpression
    : Expression '\\' LineTerminator? Expression
    ;

通常の除算演算子は、次の型に対して定義されます。

  • SingleDouble. 商は、IEEE 754 算術の規則に従って計算されます。

  • Decimal。 右オペランドの値が 0 の場合、 System.DivideByZeroException 例外がスローされます。 結果の値が 10 進形式で表すには大きすぎる場合は、 System.OverflowException 例外がスローされます。 結果の値が小さすぎて 10 進形式で表すには、結果は 0 になります。 丸める前の結果のスケールは、正確な結果と同じ結果を保持する優先スケールに最も近いスケールです。 推奨されるスケールは、1 番目のオペランドの小数点以下桁数で、2 番目のオペランドの小数点以下桁数を小さくします。

通常の演算子解決規則に従うと、 ByteShortIntegerLong などの型のオペランド間で純粋に正規除算を行うと、両方のオペランドが型 Decimalに変換されます。 ただし、どちらの型も Decimalされていないときに除算演算子に対して演算子解決を行う場合、 DoubleDecimalよりも狭いと見なされます。 Double除算はDecimal除算よりも効率的であるため、この規則に従います。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー する する する する する する する する する De Si する エラー エラー する Ob
SB する する する する する する する する De Si する エラー エラー する Ob
単位 する する する する する する する De Si する エラー エラー する Ob
Sh する する する する する する De Si する エラー エラー する Ob
米国 する する する する する De Si する エラー エラー する Ob
する する する する De Si する エラー エラー する Ob
UI する する する De Si する エラー エラー する Ob
Lo する する De Si する エラー エラー する Ob
UL する De Si する エラー エラー する Ob
De De Si する エラー エラー する Ob
Si Si する エラー エラー する Ob
すべきこと する エラー エラー する Ob
Da エラー エラー エラー エラー
Ch エラー エラー エラー
する Ob
Ob Ob

整数除算演算子は、 ByteSByteUShortShortUIntegerIntegerULong、および Longに対して定義されます。 右オペランドの値が 0 の場合、 System.DivideByZeroException 例外がスローされます。 除算によって結果が 0 に丸められます。結果の絶対値は、2 つのオペランドの商の絶対値より小さい、可能な最大の整数です。 2 つのオペランドが同じ符号を持つ場合は 0 または正、2 つのオペランドが反対の符号を持つ場合は 0 または負になります。 左オペランドが負の SByteShortInteger、または Longの最大値で、右オペランドが -1場合、オーバーフローが発生します。整数オーバーフロー チェックがオンの場合、 System.OverflowException 例外がスローされます。 それ以外の場合、オーバーフローは報告されず、結果は左オペランドの値になります。

"注: 符号なし型の 2 つのオペランドは常に 0 または正であるため、結果は常に 0 または正になります。 式の結果は常に 2 つのオペランドの最大値以下であるため、オーバーフローを発生させることはできません。 そのため、2 つの符号なし整数による整数除算では、整数オーバーフロー チェックは実行されません。 結果は、左側のオペランドの型になります。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー Sh エスビー Sh Sh Lo Lo Lo Lo Lo Lo エラー エラー Lo Ob
SB エスビー Sh Sh Lo Lo Lo Lo Lo Lo エラー エラー Lo Ob
単位 によって Sh アメリカ UI Lo UL規格 Lo Lo Lo エラー エラー Lo Ob
Sh Sh Lo Lo Lo Lo Lo Lo エラー エラー Lo Ob
米国 アメリカ UI Lo UL規格 Lo Lo Lo エラー エラー Lo Ob
Lo Lo Lo Lo Lo Lo エラー エラー Lo Ob
UI UI Lo UL規格 Lo Lo Lo エラー エラー Lo Ob
Lo Lo Lo Lo Lo Lo エラー エラー Lo Ob
UL UL規格 Lo Lo Lo エラー エラー Lo Ob
De Lo Lo Lo エラー エラー Lo Ob
Si Lo Lo エラー エラー Lo Ob
すべきこと Lo エラー エラー Lo Ob
Da エラー エラー エラー エラー
Ch エラー エラー エラー
Lo Ob
Ob Ob

Mod 演算子

Mod (剰余) 演算子は、2 つのオペランド間の除算の剰余を計算します。

ModuloOperatorExpression
    : Expression 'Mod' LineTerminator? Expression
    ;

Mod演算子は、次の型に対して定義されます。

  • ByteSByteUShortShortUIntegerIntegerULongLongx Mod y の結果は、 x - (x \ y) * yによって生成される値です。 yが 0 の場合、System.DivideByZeroException例外がスローされます。 剰余演算子によってオーバーフローが発生することはありません。

  • SingleDouble. 残りの部分は、IEEE 754 算術の規則に従って計算されます。

  • Decimal。 右オペランドの値が 0 の場合、 System.DivideByZeroException 例外がスローされます。 結果の値が 10 進形式で表すには大きすぎる場合は、 System.OverflowException 例外がスローされます。 結果の値が小さすぎて 10 進形式で表すには、結果は 0 になります。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー Sh エスビー Sh Sh Lo Lo De De Si する エラー エラー する Ob
SB エスビー Sh Sh Lo Lo De De Si する エラー エラー する Ob
単位 によって Sh アメリカ UI Lo UL規格 De Si する エラー エラー する Ob
Sh Sh Lo Lo De De Si する エラー エラー する Ob
米国 アメリカ UI Lo UL規格 De Si する エラー エラー する Ob
Lo Lo De De Si する エラー エラー する Ob
UI UI Lo UL規格 De Si する エラー エラー する Ob
Lo Lo De De Si する エラー エラー する Ob
UL UL規格 De Si する エラー エラー する Ob
De De Si する エラー エラー する Ob
Si Si する エラー エラー する Ob
すべきこと する エラー エラー する Ob
Da エラー エラー エラー エラー
Ch エラー エラー エラー
する Ob
Ob Ob

指数演算子

指数演算子は、2 番目のオペランドの累乗に上げられた最初のオペランドを計算します。

ExponentOperatorExpression
    : Expression '^' LineTerminator? Expression
    ;

指数演算子は、型 Doubleに対して定義されます。 この値は、IEEE 754 算術の規則に従って計算されます。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー する する する する する する する する する する する する エラー エラー する Ob
SB する する する する する する する する する する する エラー エラー する Ob
単位 する する する する する する する する する する エラー エラー する Ob
Sh する する する する する する する する する エラー エラー する Ob
米国 する する する する する する する する エラー エラー する Ob
する する する する する する する エラー エラー する Ob
UI する する する する する する エラー エラー する Ob
Lo する する する する する エラー エラー する Ob
UL する する する する エラー エラー する Ob
De する する する エラー エラー する Ob
Si する する エラー エラー する Ob
すべきこと する エラー エラー する Ob
Da エラー エラー エラー エラー
Ch エラー エラー エラー
する Ob
Ob Ob

リレーショナル演算子

関係演算子は、値を相互に比較します。 比較演算子は、 =<><><=、および >=です。

RelationalOperatorExpression
    : Expression '=' LineTerminator? Expression
    | Expression '<' '>' LineTerminator? Expression
    | Expression '<' LineTerminator? Expression
    | Expression '>' LineTerminator? Expression
    | Expression '<' '=' LineTerminator? Expression
    | Expression '>' '=' LineTerminator? Expression
    ;

すべての関係演算子は、 Boolean 値になります。

関係演算子には、次の一般的な意味があります。

  • =演算子は、2 つのオペランドが等しいかどうかをテストします。

  • <>演算子は、2 つのオペランドが等しくないかどうかをテストします。

  • <演算子は、最初のオペランドが 2 番目のオペランドより小さいかどうかをテストします。

  • >演算子は、最初のオペランドが 2 番目のオペランドより大きいかどうかをテストします。

  • <=演算子は、最初のオペランドが 2 番目のオペランド以下かどうかをテストします。

  • >=演算子は、最初のオペランドが 2 番目のオペランド以上かどうかをテストします。

関係演算子は、次の型に対して定義されます。

  • Boolean。 演算子は、2 つのオペランドの真偽値を比較します。 True は、数値と一致する False未満であると見なされます。

  • ByteSByteUShortShortUIntegerIntegerULong、および Long。 演算子は、2 つの整数オペランドの数値を比較します。

  • SingleDouble. 演算子は、IEEE 754 標準の規則に従ってオペランドを比較します。

  • Decimal。 演算子は、2 つの 10 進オペランドの数値を比較します。

  • Date。 演算子は、2 つの日付/時刻値を比較した結果を返します。

  • Char。 演算子は、2 つの Unicode 値を比較した結果を返します。

  • String。 演算子は、バイナリ比較またはテキスト比較を使用して 2 つの値を比較した結果を返します。 使用される比較は、コンパイル環境と Option Compare ステートメントによって決まります。 バイナリ比較では、各文字列内の各文字の数値 Unicode 値が同じかどうかを判断します。 テキスト比較は、.NET Framework で使用されている現在のカルチャに基づいて Unicode テキスト比較を行います。 文字列比較を行う場合、null 値は文字列リテラルの ""と同じです。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー ボー エスビー Sh Sh Lo Lo De De Si する エラー エラー ボー Ob
SB エスビー Sh Sh Lo Lo De De Si する エラー エラー する Ob
単位 によって Sh アメリカ UI Lo UL規格 De Si する エラー エラー する Ob
Sh Sh Lo Lo De De Si する エラー エラー する Ob
米国 アメリカ UI Lo UL規格 De Si する エラー エラー する Ob
Lo Lo De De Si する エラー エラー する Ob
UI UI Lo UL規格 De Si する エラー エラー する Ob
Lo Lo De De Si する エラー エラー する Ob
UL UL規格 De Si する エラー エラー する Ob
De De Si する エラー エラー する Ob
Si Si する エラー エラー する Ob
すべきこと する エラー エラー する Ob
Da Da エラー Da Ob
Ch Ch Ob
Ob
Ob Ob

Like 演算子

Like演算子は、文字列が特定のパターンと一致するかどうかを決定します。

LikeOperatorExpression
    : Expression 'Like' LineTerminator? Expression
    ;

Like演算子は、String型に対して定義されます。 最初のオペランドは一致する文字列であり、2 番目のオペランドは照合するパターンです。 パターンは Unicode 文字で構成されます。 次の文字シーケンスには特別な意味があります。

  • 文字 ? は、任意の 1 文字と一致します。

  • 文字 * は 0 個以上の文字と一致します。

  • 文字 # は、任意の 1 桁 (0 から 9) と一致します。

  • 角かっこ ([ab...]) で囲まれた文字の一覧は、リスト内の任意の 1 文字と一致します。

  • 角かっこで囲まれ、前に感嘆符 ([!ab...]) が付いた文字の一覧は、文字リストにない任意の 1 文字と一致します。

  • ハイフン (-) で区切られた文字リスト内の 2 文字は、最初の文字で始まり、2 番目の文字で終わる Unicode 文字の範囲を指定します。 2 番目の文字が最初の文字よりも後の並べ替え順序でない場合は、実行時例外が発生します。 文字リストの先頭または末尾に表示されるハイフンは、それ自体を指定します。

特殊文字の左角かっこ ([)、疑問符 (?)、数字記号 (#)、アスタリスク (*) と一致させるには、角かっこで囲む必要があります。 右角かっこ (]) は、グループ内で使用してそれ自体に一致させることはできませんが、グループの外部で個々の文字として使用できます。 文字シーケンス [] は、文字列リテラルの ""と見なされます。

文字の比較と文字リストの順序は、使用されている比較の種類によって異なります。 バイナリ比較を使用している場合、文字の比較と順序は数値の Unicode 値に基づいています。 テキスト比較を使用している場合、文字の比較と順序は、.NET Framework で使用されている現在のロケールに基づきます。

一部の言語では、アルファベット内の特殊文字は 2 つの別々の文字を表し、その逆も同様です。 たとえば、複数の言語で文字 æ を使用して文字 ae が一緒に表示される場合は、文字 ^O を使用して文字 Ôを表すことができます。 テキスト比較を使用する場合、 Like 演算子はこのような文化的等価性を認識します。 その場合、パターンまたは文字列のいずれかで 1 つの特殊文字が出現すると、もう一方の文字列の等価の 2 文字シーケンスと一致します。 同様に、角かっこで囲まれたパターン内の 1 つの特殊文字 (それ自体、リスト内、または範囲内) は、文字列内の等価の 2 文字シーケンスに一致し、その逆も同様です。

両方のオペランドがNothingされているか、一方のオペランドがStringへの組み込み変換を持ち、もう一方のオペランドがNothingLike式では、Nothingは空の文字列リテラル ""であるかのように扱われます。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー Ob
SB Ob
単位 Ob
Sh Ob
米国 Ob
Ob
UI Ob
Lo Ob
UL Ob
De Ob
Si Ob
すべきこと Ob
Da Ob
Ch Ob
Ob
Ob Ob

連結演算子

ConcatenationOperatorExpression
    : Expression '&' LineTerminator? Expression
    ;

連結演算子は、組み込み値型の null 許容バージョンを含め、すべての組み込み型に対して定義されます。 また、上記の型と System.DBNullを連結するために定義されます。これは、 Nothing 文字列として扱われます。 連結演算子は、すべてのオペランドを Stringに変換します。式では、厳密なセマンティクスが使用されているかどうかに関係なく、 String へのすべての変換が拡大されていると見なされます。 System.DBNull値は、Stringとして型指定Nothingリテラルに変換されます。 値がNothingされた null 許容値型も、実行時エラーをスローするのではなく、Stringとして型指定されたリテラル Nothingに変換されます。

連結演算では、2 つのオペランドを左から右に順に連結した文字列が返されます。 Nothing値は、空の文字列リテラル ""であるかのように扱われます。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー Ob
SB Ob
単位 Ob
Sh Ob
米国 Ob
Ob
UI Ob
Lo Ob
UL Ob
De Ob
Si Ob
すべきこと Ob
Da Ob
Ch Ob
Ob
Ob Ob

論理演算子

AndNotOr、およびXor演算子は論理演算子と呼ばれます。

LogicalOperatorExpression
    : 'Not' Expression
    | Expression 'And' LineTerminator? Expression
    | Expression 'Or' LineTerminator? Expression
    | Expression 'Xor' LineTerminator? Expression
    ;

論理演算子は次のように評価されます。

  • Booleanの場合は、次のように入力します。

    • 論理 And 演算は、その 2 つのオペランドに対して実行されます。

    • 論理 Not 演算はそのオペランドに対して実行されます。

    • 論理 Or 演算は、その 2 つのオペランドに対して実行されます。

    • 論理排他Or 演算は、その 2 つのオペランドに対して実行されます。

  • ByteSByteUShortShortUIntegerIntegerULongLong、およびすべての列挙型の場合、指定された演算は、2 つのオペランドのバイナリ表現の各ビットに対して実行されます。

    • And: 両方のビットが 1 の場合、結果ビットは 1 になります。それ以外の場合、結果ビットは 0 になります。

    • Not: ビットが 0 の場合、結果ビットは 1 になります。それ以外の場合、結果ビットは 1 です。

    • Or: いずれかのビットが 1 の場合、結果ビットは 1 になります。それ以外の場合、結果ビットは 0 になります。

    • Xor: いずれかのビットが 1 で、両方のビットではない場合、結果ビットは 1 になります。それ以外の場合、結果ビットは 0 です (つまり、1 Xor 0 = 1、1 Xor 1 = 0)。

  • 論理演算子 AndOrBoolean?型に対して解除されると、次のように 3 つの値を持つブール型ロジックが含まれるように拡張されます。

    • And 両方のオペランドが true の場合は true に評価されます。いずれかのオペランドが false の場合は false。それ以外の場合 Nothing

    • Or いずれかのオペランドが true の場合は true に評価されます。false は両方のオペランドが false です。それ以外の場合 Nothing

例えば次が挙げられます。

Module Test
    Sub Main()
        Dim x?, y? As Boolean

        x = Nothing
        y = True 

        If x Or y Then
            ' Will execute
        End If
    End Sub
End Module

"注: 論理演算子の AndOr は、ブール式で使用できる任意の型 (つまり、 IsTrueIsFalseを実装する型) に対して、ブール式で使用できる任意の型の AndAlsoOrElse ショートサーキットを使用して解除するのが理想的です。 残念ながら、3 値リフティングは Boolean?にのみ適用されるため、3 値ロジックを必要とするユーザー定義型は、null 許容バージョンの And 演算子と Or 演算子を定義することによって手動で行う必要があります。

これらの演算からのオーバーフローは発生しません。 列挙型演算子は、列挙型の基になる型に対してビットごとの操作を実行しますが、戻り値は列挙型です。

操作の種類ではありません:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー エスビー によって Sh アメリカ UI Lo UL規格 Lo Lo Lo エラー エラー Lo Ob

または、Xor 操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー ボー エスビー Sh Sh Lo Lo Lo Lo Lo Lo エラー エラー ボー Ob
SB エスビー Sh Sh Lo Lo Lo Lo Lo Lo エラー エラー Lo Ob
単位 によって Sh アメリカ UI Lo UL規格 Lo Lo Lo エラー エラー Lo Ob
Sh Sh Lo Lo Lo Lo Lo Lo エラー エラー Lo Ob
米国 アメリカ UI Lo UL規格 Lo Lo Lo エラー エラー Lo Ob
Lo Lo Lo Lo Lo Lo エラー エラー Lo Ob
UI UI Lo UL規格 Lo Lo Lo エラー エラー Lo Ob
Lo Lo Lo Lo Lo Lo エラー エラー Lo Ob
UL UL規格 Lo Lo Lo エラー エラー Lo Ob
De Lo Lo Lo エラー エラー Lo Ob
Si Lo Lo エラー エラー Lo Ob
すべきこと Lo エラー エラー Lo Ob
Da エラー エラー エラー エラー
Ch エラー エラー エラー
Lo Ob
Ob Ob

短絡論理演算子

AndAlso演算子とOrElse演算子は、AndおよびOr論理演算子の短絡バージョンです。

ShortCircuitLogicalOperatorExpression
    : Expression 'AndAlso' LineTerminator? Expression
    | Expression 'OrElse' LineTerminator? Expression
    ;

ショートサーキット動作のため、最初のオペランドを評価した後に演算子の結果がわかっている場合、2 番目のオペランドは実行時に評価されません。

短絡論理演算子は、次のように評価されます。

  • AndAlso演算の最初のオペランドがFalseに評価されるか、IsFalse演算子から True を返す場合、式は最初のオペランドを返します。 それ以外の場合は、2 番目のオペランドが評価され、2 つの結果に対して論理 And 演算が実行されます。

  • OrElse演算の最初のオペランドがTrueに評価されるか、IsTrue演算子から True を返す場合、式は最初のオペランドを返します。 それ以外の場合、2 番目のオペランドが評価され、その 2 つの結果に対して論理 Or 演算が実行されます。

AndAlso演算子とOrElse演算子は、型Boolean、または次の演算子をオーバーロードする任意の型Tに対して定義されます。

Public Shared Operator IsTrue(op As T) As Boolean
Public Shared Operator IsFalse(op As T) As Boolean

対応する And または Or 演算子をオーバーロードします。

Public Shared Operator And(op1 As T, op2 As T) As T
Public Shared Operator Or(op1 As T, op2 As T) As T

AndAlso演算子またはOrElse演算子を評価する場合、最初のオペランドは 1 回だけ評価され、2 番目のオペランドは 1 回だけ評価または評価されません。 たとえば、次のコードを考えてみましょう。

Module Test
    Function TrueValue() As Boolean
        Console.Write(" True")
        Return True
    End Function

    Function FalseValue() As Boolean
        Console.Write(" False")
        Return False
    End Function

    Sub Main()
        Console.Write("And:")
        If FalseValue() And TrueValue() Then
        End If
        Console.WriteLine()

        Console.Write("Or:")
        If TrueValue() Or FalseValue() Then
        End If
        Console.WriteLine()

        Console.Write("AndAlso:")
        If FalseValue() AndAlso TrueValue() Then
        End If
        Console.WriteLine()

        Console.Write("OrElse:")
        If TrueValue() OrElse FalseValue() Then
        End If
        Console.WriteLine()
    End Sub
End Module

次の結果が出力されます。

And: False True
Or: True False
AndAlso: False
OrElse: True

AndAlso演算子とOrElse演算子のリフトされた形式では、最初のオペランドが null Boolean?の場合、2 番目のオペランドが評価されますが、結果は常に null Boolean?になります。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
ボー ボー ボー ボー ボー ボー ボー ボー ボー ボー ボー ボー ボー エラー エラー ボー Ob
SB ボー ボー ボー ボー ボー ボー ボー ボー ボー ボー ボー エラー エラー ボー Ob
単位 ボー ボー ボー ボー ボー ボー ボー ボー ボー ボー エラー エラー ボー Ob
Sh ボー ボー ボー ボー ボー ボー ボー ボー ボー エラー エラー ボー Ob
米国 ボー ボー ボー ボー ボー ボー ボー ボー エラー エラー ボー Ob
ボー ボー ボー ボー ボー ボー ボー エラー エラー ボー Ob
UI ボー ボー ボー ボー ボー ボー エラー エラー ボー Ob
Lo ボー ボー ボー ボー ボー エラー エラー ボー Ob
UL ボー ボー ボー ボー エラー エラー ボー Ob
De ボー ボー ボー エラー エラー ボー Ob
Si ボー ボー エラー エラー ボー Ob
すべきこと ボー エラー エラー ボー Ob
Da エラー エラー エラー エラー
Ch エラー エラー エラー
ボー Ob
Ob Ob

シフト演算子

二項演算子は、ビットシフト演算を実行<<>>

ShiftOperatorExpression
    : Expression '<' '<' LineTerminator? Expression
    | Expression '>' '>' LineTerminator? Expression
    ;

演算子は、 ByteSByteUShortShortUIntegerIntegerULong 、および Long 型に対して定義されます。 他の二項演算子とは異なり、シフト演算の結果型は、演算子が左オペランドのみを持つ単項演算子であるかのように決定されます。 右側のオペランドの型は、 Integer に暗黙的に変換できる必要があり、演算の結果の型の決定には使用されません。

<<演算子を使用すると、最初のオペランドのビットはシフト量で指定された桁数のままシフトされます。 結果の種類の範囲外の上位ビットは破棄され、下位の空きビット位置は 0 で埋められます。

>>演算子を使用すると、最初のオペランドのビットがシフト量で指定された位置の数だけ右にシフトされます。 下位ビットは破棄され、左オペランドが正の場合は上位の空きビット位置が 0 に設定され、負の場合は 1 に設定されます。 左オペランドの型が ByteUShortUInteger、または ULong の場合、空いている上位ビットは 0 で塗りつぶされます。

シフト演算子は、最初のオペランドの基になる表現のビットを 2 番目のオペランドの量だけシフトします。 2 番目のオペランドの値が最初のオペランドのビット数より大きい場合、または負の値である場合、シフト量はSizeMaskRightOperand And SizeMask計算されます。

LeftOperand 型 SizeMask
ByteSByte 7 (&H7)
UShortShort 15 (&HF)
UIntegerInteger 31 (&H1F)
ULongLong 63 (&H3F)

シフト量が 0 の場合、演算の結果は最初のオペランドの値と同じです。 これらの演算からのオーバーフローは発生しません。

操作の種類:

ボー SB 単位 Sh 米国 UI Lo UL De Si すべきこと Da Ch Ob
Sh エスビー によって Sh アメリカ UI Lo UL規格 Lo Lo Lo エラー エラー Lo Ob

Boolean 式

ブール式は、true かどうか、または false であるかどうかを確認するためにテストできる式です。

BooleanExpression
    : Expression
    ;

T は、好みの順序でブール式で使用できます。

  • TBoolean または Boolean?

  • T の拡大変換が行われます。 Boolean

  • T の拡大変換が行われます。 Boolean?

  • T は、 IsTrueIsFalseの 2 つの擬似演算子を定義します。

  • Tには、Boolean から Boolean? への変換を伴わないBoolean?への縮小変換があります。

  • T には、 Booleanへの縮小変換があります。

"注: Option Strictがオフの場合、Booleanへの縮小変換を持つ式はコンパイル時エラーなしで受け入れられますが、言語が存在する場合はIsTrue演算子を使用することに注意してください。 これは、 Option Strict は言語によって受け入れられていないものだけを変更し、式の実際の意味を変更しないためです。 したがって、 IsTrue は、 Option Strictに関係なく、縮小変換よりも常に優先される必要があります。

たとえば、次のクラスでは、 Booleanへの拡大変換は定義されていません。 その結果、 If ステートメントで使用すると、 IsTrue 演算子が呼び出されます。

Class MyBool
    Public Shared Widening Operator CType(b As Boolean) As MyBool
        ...
    End Operator

    Public Shared Narrowing Operator CType(b As MyBool) As Boolean
        ...
    End Operator

    Public Shared Operator IsTrue(b As MyBool) As Boolean
        ...
    End Operator

    Public Shared Operator IsFalse(b As MyBool) As Boolean
        ...
    End Operator
End Class

Module Test
    Sub Main()
        Dim b As New MyBool

        If b Then Console.WriteLine("True")
    End Sub
End Module

ブール式が Boolean または Boolean?として型指定または変換される場合、値が True の場合は true、それ以外の場合は false になります。

それ以外の場合、ブール式はIsTrue演算子を呼び出し、演算子がTrue返された場合はTrueを返します。それ以外の場合は false です (ただし、IsFalse 演算子は呼び出しません)。

次の例では、 Integer には Booleanへの縮小変換があるため、null Integer?Boolean? (null Boolean) と Boolean (例外をスローする) の両方に縮小変換されます。 Boolean?への縮小変換が推奨されるため、ブール式としての "i" の値はFalse

Dim i As Integer? = Nothing
If i Then Console.WriteLine()

ラムダ式

ラムダ式は、ラムダ メソッドと呼ばれる匿名メソッドを定義します。 ラムダ メソッドを使用すると、デリゲート型を受け取る他のメソッドに "インライン" メソッドを簡単に渡すことができます。

LambdaExpression
    : SingleLineLambda
    | MultiLineLambda
    ;

SingleLineLambda
    : LambdaModifier* 'Function' ( OpenParenthesis ParameterList? CloseParenthesis )? Expression
    | 'Sub' ( OpenParenthesis ParameterList? CloseParenthesis )? Statement
    ;

MultiLineLambda
    : MultiLineFunctionLambda
    | MultiLineSubLambda
    ;

MultiLineFunctionLambda
    : LambdaModifier? 'Function' ( OpenParenthesis ParameterList? CloseParenthesis )? ( 'As' TypeName )? LineTerminator
      Block
      'End' 'Function'
    ;

MultiLineSubLambda
    : LambdaModifier? 'Sub' ( OpenParenthesis ParameterList? CloseParenthesis )? LineTerminator
      Block
      'End' 'Sub'
    ;

LambdaModifier
    : 'Async' | 'Iterator'
    ;

例:

Module Test
    Delegate Function IntFunc(x As Integer) As Integer

    Sub Apply(a() As Integer, func As IntFunc)
        For index As Integer = 0 To a.Length - 1
            a(index) = func(a(index))
        Next index
    End Sub

    Sub Main()
        Dim a() As Integer = { 1, 2, 3, 4 }

        Apply(a, Function(x As Integer) x * 2)

        For Each value In a
            Console.Write(value & " ")
        Next value
    End Sub
End Module

は出力されます。

2 4 6 8

ラムダ式は、省略可能な修飾子 Async または Iteratorで始まり、その後にキーワード Function または Sub とパラメーター リストが続きます。 ラムダ式のパラメーターは、 Optional または ParamArray 宣言できず、属性を持つことはできません。 通常のメソッドとは異なり、ラムダ メソッドのパラメーター型を省略しても、 Objectが自動的に推論されることはありません。 代わりに、ラムダ メソッドが再分類されると、省略されたパラメーター型と ByRef 修飾子がターゲット型から推論されます。 前の例では、ラムダ式はFunction(x) x * 2として記述された可能性があり、ラムダ メソッドを使用してIntFuncデリゲート型のインスタンスを作成するときにIntegerされるxの型を推論しました。 ローカル変数の推論とは異なり、ラムダ メソッド パラメーターで型が省略されていても、配列または null 許容名修飾子がある場合は、コンパイル時エラーが発生します。

正規表現は、Async修飾子もIterator修飾子もないです。

反復子ラムダ式は、Iterator修飾子を持ち、Async修飾子を持たない式です。 関数である必要があります。 値に再分類する場合は、戻り値の型がIEnumeratorIEnumerable、または一部のTIEnumerator(Of T)またはIEnumerable(Of T)であり、ByRef パラメーターを持たないデリゲート型の値にのみ再分類できます。

非同期ラムダ式は、Async修飾子を持ち、Iterator修飾子を持たない式です。 非同期サブラムダは、ByRef パラメーターのないサブデリゲート型の値にのみ再分類できます。 非同期関数ラムダは、戻り値の型が一部のTに対してTaskまたはTask(Of T)であり、ByRef パラメーターがない関数デリゲート型の値にのみ再分類できます。

ラムダ式には、1 行または複数行のいずれかを指定できます。 単一行 Function ラムダ式には、ラムダ メソッドから返される値を表す 1 つの式が含まれています。 単一行 Sub ラムダ式には、閉じる StatementTerminatorのない 1 つのステートメントが含まれています。 例えば次が挙げられます。

Module Test
    Sub Do(a() As Integer, action As Action(Of Integer))
        For index As Integer = 0 To a.Length - 1
            action(a(index))
        Next index
    End Sub

    Sub Main()
        Dim a() As Integer = { 1, 2, 3, 4 }

        Do(a, Sub(x As Integer) Console.WriteLine(x))
    End Sub
End Module

1 行のラムダ コンストラクトは、他のすべての式やステートメントよりもバインドが少なくなります。 したがって、たとえば、"Function() x + 5" は "(Function() x) + 5" ではなく "Function() (x+5)"" に相当します。 あいまいさを回避するために、単一行 Sub ラムダ式に Dim ステートメントまたはラベル宣言ステートメントを含めないようにすることができます。 また、かっこで囲まれていない限り、単一行 Sub ラムダ式の直後にコロン ":"、メンバー アクセス演算子 "."、ディクショナリ メンバー アクセス演算子 "!" または開いているかっこ "() が続かない場合があります。 ブロック ステートメント (WithSyncLock, If...EndIfWhileForDoUsing) やOnErrorResumeを含めないようにすることができます。

"注: ラムダ式 Function(i) x=iでは、本文は として解釈されます ( xi が等しいかどうかをテストします)。 ただし、ラムダ式 Sub(i) x=iでは、本文はステートメントとして解釈されます ( ixに割り当てます)。

複数行のラムダ式にはステートメント ブロックが含まれており、適切な End ステートメント (つまり、 End Function または End Sub) で終わる必要があります。 通常のメソッドと同様に、複数行のラムダ メソッドの Function または Sub ステートメントと End ステートメントは、独自の行に置く必要があります。 例えば次が挙げられます。

' Error: Function statement must be on its own line!
Dim x = Sub(x As Integer) : Console.WriteLine(x) : End Sub

' OK
Dim y = Sub(x As Integer)
               Console.WriteLine(x)
          End Sub

複数行 Function ラムダ式は戻り値の型を宣言できますが、属性を配置することはできません。 複数行 Function ラムダ式で戻り値の型が宣言されていないが、ラムダ式が使用されているコンテキストから戻り値の型を推論できる場合は、その戻り値の型が使用されます。 それ以外の場合、関数の戻り値の型は次のように計算されます。

  • 正規表現では、戻り値の型は、ステートメント ブロック内のすべての Return ステートメントの式の主要な型です。

  • 非同期ラムダ式では、戻り値の型はTask(Of T)Tステートメント ブロック内のすべてのReturnステートメント内の式の主要な型です。

  • 反復子ラムダ式では、戻り値の型はIEnumerable(Of T)Tステートメント ブロック内のすべてのYieldステートメント内の式の主要な型です。

例えば次が挙げられます。

Function f(min As Integer, max As Integer) As IEnumerable(Of Integer)
    If min > max Then Throw New ArgumentException()
    Dim x = Iterator Function()
                  For i = min To max
                    Yield i
                Next
               End Function

    ' infers x to be a delegate with return type IEnumerable(Of Integer)
    Return x()
End Function

いずれの場合も、 Return (それぞれ Yield) ステートメントがない場合、またはその中に主要な型がなく、厳密なセマンティクスが使用されている場合は、コンパイル時エラーが発生します。それ以外の場合、優先型は暗黙的に Object

戻り値の型は、到達できない場合でも、すべての Return ステートメントから計算されることに注意してください。 例えば次が挙げられます。

' Return type is Double
Dim x = Function()
              Return 10
               Return 10.50
          End Function

変数の名前がないため、暗黙的な戻り変数はありません。

複数行のラムダ式内のステートメント ブロックには、次の制限があります。

  • On Error ステートメントと Resume ステートメントは許可されませんが、 Try ステートメントは許可されます。

  • 複数行のラムダ式で静的ローカルを宣言することはできません。

  • 複数行のラムダ式のステートメント ブロックに対して分岐または分岐することはできませんが、その中には通常の分岐規則が適用されます。 例えば次が挙げられます。

    Label1:
    Dim x = Sub()
                   ' Error: Cannot branch out
                   GoTo Label1
    
                   ' OK: Wholly within the lamba.
                   GoTo Label2:
              Label2:
              End Sub
    
    ' Error: Cannot branch in
    GoTo Label2
    

ラムダ式は、包含型で宣言された匿名メソッドとほぼ同じです。 最初の例は、次とほぼ同じです。

Module Test
    Delegate Function IntFunc(x As Integer) As Integer

    Sub Apply(a() As Integer, func As IntFunc)
        For index As Integer = 0 To a.Length - 1
            a(index) = func(a(index))
        Next index
    End Sub

    Function $Lambda1(x As Integer) As Integer
        Return x * 2
    End Function

    Sub Main()
        Dim a() As Integer = { 1, 2, 3, 4 }

        Apply(a, AddressOf $Lambda1)

        For Each value In a
            Console.Write(value & " ")
        Next value
    End Sub
End Module

クロージャ

ラムダ式は、ローカル変数や、包含メソッドとラムダ式で定義されているパラメーターを含む、スコープ内のすべての変数にアクセスできます。 ラムダ式がローカル変数またはパラメーターを参照する場合、ラムダ式は、参照されている変数をクロージャにキャプチャします。 クロージャはスタックではなくヒープ上に存在するオブジェクトであり、変数がキャプチャされると、変数へのすべての参照がクロージャにリダイレクトされます。 これにより、ラムダ式は、包含メソッドが完了した後でも、ローカル変数とパラメーターを参照し続けられます。 例えば次が挙げられます。

Module Test
    Delegate Function D() As Integer

    Function M() As D
        Dim x As Integer = 10
        Return Function() x
    End Function

    Sub Main()
        Dim y As D = M()

        ' Prints 10
        Console.WriteLine(y())
    End Sub
End Module

は、次とほぼ同じです。

Module Test
    Delegate Function D() As Integer

    Class $Closure1
        Public x As Integer

        Function $Lambda1() As Integer
            Return x
        End Function
    End Class

    Function M() As D
        Dim c As New $Closure1()
        c.x = 10
        Return AddressOf c.$Lambda1
    End Function

    Sub Main()
        Dim y As D = M()

        ' Prints 10
        Console.WriteLine(y())
    End Sub
End Module

クロージャは、ローカル変数が宣言されているブロックに入るたびにローカル変数の新しいコピーをキャプチャしますが、新しいコピーがある場合は、前のコピーの値で初期化されます。 例えば次が挙げられます。

Module Test
    Delegate Function D() As Integer

    Function M() As D()
        Dim a(9) As D

        For i As Integer = 0 To 9
            Dim x
            a(i) = Function() x
            x += 1
        Next i

        Return a
    End Function

    Sub Main()
        Dim y() As D = M()

        For i As Integer = 0 To 9
            Console.Write(y(i)() & " ")
        Next i
    End Sub
End Module

プリント

1 2 3 4 5 6 7 8 9 10

代わりに

9 9 9 9 9 9 9 9 9 9

クロージャはブロックに入るときに初期化する必要があるため、そのブロックの外側からクロージャのあるブロックに GoTo することは許可されませんが、クロージャを持つブロックに Resume することはできます。 例えば次が挙げられます。

Module Test
    Sub Main()
        Dim a = 10

        If a = 10 Then
L1:
            Dim x = Function() a

            ' Valid, source is within block
            GoTo L2
L2:
        End If

        ' ERROR: target is inside block with closure
        GoTo L1
    End Sub
End Module

これらはクロージャにキャプチャできないため、ラムダ式の内部に次のように表示することはできません。

  • 参照パラメーター。

  • Meの型がクラスでない場合は、インスタンス式 (MeMyClassMyBase)。

ラムダ式が式の一部である場合は、匿名型作成式のメンバー。 例えば次が挙げられます。

' Error: Lambda cannot refer to anonymous type field
Dim x = New With { .a = 12, .b = Function() .a }

ReadOnly インスタンス コンストラクター内のインスタンス変数、または値以外のコンテキストで変数が使用される共有コンストラクターの共有変数 ReadOnly します。 例えば次が挙げられます。

Class C1
    ReadOnly F1 As Integer

    Sub New()
        ' Valid, doesn't modify F1
        Dim x = Function() F1

        ' Error, tries to modify F1
        Dim f = Function() ModifyValue(F1)
    End Sub

    Sub ModifyValue(ByRef x As Integer)
    End Sub
End Class

クエリ式

クエリ式は、クエリ可能なコレクションの要素に一連のクエリ演算子を適用する式です。 たとえば、次の式は、 Customer オブジェクトのコレクションを受け取り、ワシントン州のすべての顧客の名前を返します。

Dim names = _
    From cust In Customers _
    Where cust.State = "WA" _
    Select cust.Name

クエリ式は、 From または Aggregate 演算子で始まる必要があり、任意のクエリ演算子で終えることができます。 クエリ式の結果は値として分類されます。式の結果の型は、式の最後のクエリ演算子の結果の型によって異なります。

QueryExpression
    : FromOrAggregateQueryOperator QueryOperator*
    ;

FromOrAggregateQueryOperator
    : FromQueryOperator
    | AggregateQueryOperator
    ;

QueryOperator
    : FromQueryOperator
    | AggregateQueryOperator
    | SelectQueryOperator
    | DistinctQueryOperator
    | WhereQueryOperator
    | OrderByQueryOperator
    | PartitionQueryOperator
    | LetQueryOperator
    | GroupByQueryOperator
    | JoinOrGroupJoinQueryOperator
    ;

JoinOrGroupJoinQueryOperator
    : JoinQueryOperator
    | GroupJoinQueryOperator
    ;

範囲変数

一部のクエリ演算子では、範囲変数と呼ばれる特殊な種類の変数が導入 されています。 範囲変数は実際の変数ではありません。代わりに、入力コレクションに対するクエリの評価中に個々の値を表します。

CollectionRangeVariableDeclarationList
    : CollectionRangeVariableDeclaration ( Comma CollectionRangeVariableDeclaration )*
    ;

CollectionRangeVariableDeclaration
    : Identifier ( 'As' TypeName )? 'In' LineTerminator? Expression
    ;

ExpressionRangeVariableDeclarationList
    : ExpressionRangeVariableDeclaration ( Comma ExpressionRangeVariableDeclaration )*
    ;

ExpressionRangeVariableDeclaration
    : Identifier ( 'As' TypeName )? Equals Expression
    ;

範囲変数のスコープは、導入クエリ演算子からクエリ式の末尾、またはクエリ演算子 (非表示にする Select など) です。 たとえば、次のクエリで

Dim waCusts = _
    From cust As Customer In Customers _
    Where cust.State = "WA"

From クエリ演算子は、Customers コレクション内の各顧客を表すCustomerとして型指定された範囲変数cust導入します。 次の Where クエリ演算子は、フィルター式で cust 範囲変数を参照して、結果のコレクションから個々の顧客をフィルター処理するかどうかを決定します。

範囲変数には、 コレクション範囲 変数と 式範囲変数の 2 種類があります。 コレクション範囲変数は、クエリ対象のコレクションの要素から値を取得します。 コレクション範囲変数宣言のコレクション式は、型がクエリ可能な値として分類する必要があります。 コレクション範囲変数の型を省略すると、コレクション式の要素型として推論されるか、コレクション式に要素型がない場合 (つまり、Cast メソッドのみを定義する) 場合にObjectされます。 コレクション式がクエリ可能でない場合 (つまり、コレクションの要素型を推論できない)、コンパイル時エラーが発生します。

式範囲変数は、コレクションではなく式によって値が計算される範囲変数です。 次の例では、 Select クエリ演算子は、2 つのフィールドから計算 cityState という名前の式範囲変数を導入しています。

Dim cityStates = _
    From cust As Customer In Customers _
    Select cityState = cust.City & "," & cust.State _
    Where cityState.Length() < 10

式範囲変数は別の範囲変数を参照するために必要ありませんが、そのような変数は疑わしい値である可能性があります。 式範囲変数に割り当てられた式は値として分類する必要があり、指定された場合は、範囲変数の型に暗黙的に変換できる必要があります。

Let 演算子内でのみ、式範囲変数の型が指定されている場合があります。 他の演算子で、またはその型が指定されていない場合は、ローカル変数の型推論を使用して範囲変数の型が決定されます。

範囲変数は、シャドウに関してローカル変数を宣言するための規則に従う必要があります。 したがって、範囲変数は、外側のメソッドまたは別の範囲変数内のローカル変数またはパラメーターの名前を非表示にすることはできません (クエリ演算子がスコープ内のすべての現在の範囲変数を明示的に非表示にしない限り)。

クエリ可能な型

クエリ式は、式をコレクション型の既知のメソッドの呼び出しに変換することによって実装されます。 これらの適切に定義されたメソッドは、クエリ可能なコレクションの要素型と、コレクションで実行されるクエリ演算子の結果の型を定義します。 各クエリ演算子は、クエリ演算子が通常変換されるメソッドを指定しますが、特定の変換は実装に依存します。 メソッドは、次のような一般的な形式を使用して仕様で提供されます。

Function Select(selector As Func(Of T, R)) As CR

メソッドには次のことが適用されます。

  • メソッドは、コレクション型のインスタンスまたは拡張メンバーである必要があり、アクセス可能である必要があります。

  • すべての型引数を推論できる場合、メソッドはジェネリックである可能性があります。

  • メソッドをオーバーロードできます。この場合、オーバーロードの解決を使用して、使用するメソッドを正確に決定します。

  • 一致するFunc型と同じシグネチャ (戻り値の型を含む) を持っている場合は、デリゲート Func型の代わりに別のデリゲート型を使用できます。

  • System.Linq.Expressions.Expression(Of D)型は、Dが、一致するFunc型と同じシグネチャ (戻り値の型を含む) を持つデリゲート型である場合、デリゲート Func型の代わりに使用できます。

  • T型は、入力コレクションの要素型を表します。 コレクション型で定義されるすべてのメソッドは、クエリ可能なコレクション型に対して同じ入力要素型を持つ必要があります。

  • S型は、結合を実行するクエリ演算子の場合の 2 番目の入力コレクションの要素型を表します。

  • K型は、キーとして機能する範囲変数のセットを持つクエリ演算子の場合のキー型を表します。

  • N型は、数値型として使用される型を表します (ただし、組み込みの数値型ではなく、ユーザー定義型の場合もあります)。

  • B型は、ブール式で使用できる型を表します。

  • クエリ演算子が結果コレクションを生成する場合、 R 型は結果コレクションの要素型を表します。 R は、クエリ演算子の終了時のスコープ内の範囲変数の数によって異なります。 1 つの範囲変数がスコープ内にある場合、 R はその範囲変数の型です。 この例では

    Dim custNames = From c In Customers
                    Select c.Name
    

    クエリの結果は、 Stringの要素型を持つコレクション型になります。 複数の範囲変数がスコープ内にある場合、 R は、スコープ内のすべての範囲変数を Key フィールドとして含む匿名型です。 この例では、次のようになります。

    Dim custNames = From c In Customers, o In c.Orders 
                    Select Name = c.Name, ProductName = o.ProductName
    

    クエリの結果は、匿名型の要素型を持つコレクション型で、String型のNameという名前の読み取り専用プロパティと、String型のProductNameという名前の読み取り専用プロパティになります。

    クエリ式内では、範囲変数を含めるために生成された匿名型は 透過的です。つまり、範囲変数は修飾なしで常に使用できます。 たとえば、前の例では、入力コレクションの要素型が匿名型であっても、Select クエリ演算子の修飾なしで範囲変数coにアクセスできます。

  • CX型はコレクション型を表し、必ずしも入力コレクション型ではなく、要素型が何らかの型X

クエリ可能なコレクション型は、優先順に次のいずれかの条件を満たす必要があります。

  • 準拠する Select メソッドを定義する必要があります。

  • 次のいずれかの方法が必要です。

    Function AsEnumerable() As CT
    Function AsQueryable() As CT
    

    クエリ可能なコレクションを取得するために呼び出すことができます。 両方の方法を指定する場合は、AsEnumerableよりもAsQueryableすることをお勧めします。

  • メソッドが必要です

    Function Cast(Of T)() As CT
    

    範囲変数の型を使用して呼び出して、クエリ可能なコレクションを生成できます。

コレクションの要素型の決定は、実際のメソッド呼び出しとは無関係に行われるため、特定のメソッドの適用性を判断できません。 したがって、既知のメソッドと一致するインスタンス メソッドがある場合、コレクションの要素型を決定する場合、既知のメソッドに一致する拡張メソッドはすべて無視されます。

クエリ演算子の変換は、式でクエリ演算子が発生した順序で行われます。 コレクション オブジェクトは、すべてのクエリ演算子で必要なすべてのメソッドを実装する必要はありませんが、すべてのコレクション オブジェクトは少なくとも Select クエリ演算子をサポートする必要があります。 必要なメソッドが存在しない場合は、コンパイル時エラーが発生します。 既知のメソッド名をバインドする場合、インターフェイスと拡張メソッドのバインドで複数の継承を行う目的で非メソッドは無視されますが、シャドウ セマンティクスは引き続き適用されます。 例えば次が挙げられます。

Class Q1
    Public Function [Select](selector As Func(Of Integer, Integer)) As Q1
    End Function
End Class

Class Q2
    Inherits Q1

    Public [Select] As Integer
End Class

Module Test
    Sub Main()
        Dim qs As New Q2()

        ' Error: Q2.Select still hides Q1.Select
        Dim zs = From q In qs Select q
    End Sub
End Module

既定のクエリ インデクサー

要素型が T で、既定のプロパティをまだ持たないクエリ可能なコレクション型はすべて、次の一般的な形式の既定のプロパティを持つと見なされます。

Public ReadOnly Default Property Item(index As Integer) As T
    Get
        Return Me.ElementAtOrDefault(index)
    End Get
End Property

既定のプロパティは、既定のプロパティ アクセス構文を使用してのみ参照できます。既定のプロパティを名前で参照することはできません。 例えば次が挙げられます。

Dim customers As IEnumerable(Of Customer) = ...
Dim customerThree = customers(2)

' Error, no such property
Dim customerFour = customers.Item(4)

コレクション型に ElementAtOrDefault メンバーがない場合は、コンパイル時エラーが発生します。

クエリ演算子から

From クエリ演算子は、クエリを実行するコレクションの個々のメンバーを表すコレクション範囲変数を導入します。

FromQueryOperator
    : LineTerminator? 'From' LineTerminator? CollectionRangeVariableDeclarationList
    ;

たとえば、クエリ式は次のようになります。

From c As Customer In Customers ...

と同等と考えることができます。

For Each c As Customer In Customers
        ...
Next c

Fromクエリ演算子が複数のコレクション範囲変数を宣言する場合、またはクエリ式の最初のFromクエリ演算子でない場合、新しいコレクション範囲変数はそれぞれ、既存の範囲変数のセットにクロス結合されます。 その結果、結合されたコレクション内のすべての要素のクロス積に対してクエリが評価されます。 たとえば、式

From c In Customers _
From e In Employees _
...

は、次と同等と考えることができます。

For Each c In Customers
    For Each e In Employees
            ...
    Next e
Next c

とまったく同じです。

From c In Customers, e In Employees ...

前のクエリ演算子で導入された範囲変数は、後の From クエリ演算子で使用できます。 たとえば、次のクエリ式では、2 番目の From クエリ演算子は、最初の範囲変数の値を参照します。

From c As Customer In Customers _
From o As Order In c.Orders _
Select c.Name, o

From クエリ演算子または複数のFromクエリ演算子内の複数の範囲変数は、コレクション型に次のメソッドのいずれかまたは両方が含まれている場合にのみサポートされます。

Function SelectMany(selector As Func(Of T, CR)) As CR
Function SelectMany(selector As Func(Of T, CS), _
                          resultsSelector As Func(Of T, S, R)) As CR

コード

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs, y In ys ...

は、通常、〘

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = _
    xs.SelectMany( _
        Function(x As Integer) ys, _
        Function(x As Integer, y As Integer) New With {x, y})...

"注: From は予約語ではありません。

クエリ結合演算子

Joinクエリ演算子は、既存の範囲変数を新しいコレクション範囲変数と結合し、等値式に基づいて要素が結合された単一のコレクションを生成します。

JoinQueryOperator
    : LineTerminator? 'Join' LineTerminator? CollectionRangeVariableDeclaration
      JoinOrGroupJoinQueryOperator? LineTerminator? 'On' LineTerminator? JoinConditionList
    ;

JoinConditionList
    : JoinCondition ( 'And' LineTerminator? JoinCondition )*
    ;

JoinCondition
    : Expression 'Equals' LineTerminator? Expression
    ;

例えば次が挙げられます。

Dim customersAndOrders = _
    From cust In Customers _
    Join ord In Orders On cust.ID Equals ord.CustomerID

等値式は、正規表現よりも制限されます。

  • どちらの式も値として分類する必要があります。

  • どちらの式も、少なくとも 1 つの範囲変数を参照する必要があります。

  • 結合クエリ演算子で宣言された範囲変数は、いずれかの式で参照する必要があり、その式は他の範囲変数を参照してはなりません。

2 つの式の型がまったく同じ型でない場合は、

  • 等値演算子が 2 つの型に対して定義されている場合、両方の式が暗黙的に変換可能であり、 Objectされていない場合は、両方の式をその型に変換します。

  • それ以外の場合、両方の式を暗黙的に変換できる主要な型がある場合は、両方の式をその型に変換します。

  • それ以外の場合は、コンパイル時エラーが発生します。

式は、効率のために等値演算子を使用するのではなく、ハッシュ値 (つまり、 GetHashCode()を呼び出すことによって) を使用して比較されます。 Joinクエリ演算子は、同じ演算子で複数の結合または等値条件を実行できます。 Join クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function Join(inner As CS, _
                  outerSelector As Func(Of T, K), _
                  innerSelector As Func(Of S, K), _
                  resultSelector As Func(Of T, S, R)) As CR

コード

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs _
            Join y In ys On x Equals y _
            ...

は、通常、〘

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = _
    xs.Join( _
        ys, _
        Function(x As Integer) x, _
        Function(y As Integer) y, _
        Function(x As Integer, y As Integer) New With {x, y})...

Note.JoinOnEquals は予約語ではありません。

Let Query 演算子

Let クエリ演算子は、式範囲変数を導入します。 これにより、後のクエリ演算子で複数回使用される中間値を 1 回計算できます。

LetQueryOperator
    : LineTerminator? 'Let' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

例えば次が挙げられます。

Dim taxedPrices = _
    From o In Orders _
    Let tax = o.Price * 0.088 _
    Where tax > 3.50 _
    Select o.Price, tax, total = o.Price + tax

は、次と同等と考えることができます。

For Each o In Orders
    Dim tax = o.Price * 0.088
    ...
Next o

Let クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function Select(selector As Func(Of T, R)) As CR

コード

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Let y = x * 10 _
            ...

は、通常、〘

Dim xs() As Integer = ...
Dim zs = _
    xs.Select(Function(x As Integer) New With {x, .y = x * 10})...

クエリ演算子の選択

Selectクエリ演算子は、式範囲変数を導入するという点でLetクエリ演算子に似ていますが、Selectクエリ演算子では、現在使用可能な範囲変数を追加するのではなく非表示にします。 また、 Select クエリ演算子によって導入された式範囲変数の型は、常にローカル変数の型推論規則を使用して推論されます。明示的な型を指定することはできません。また、型を推論できない場合は、コンパイル時エラーが発生します。

SelectQueryOperator
    : LineTerminator? 'Select' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

たとえば、クエリでは次のようになります。

Dim smiths = _
    From cust In Customers _
    Select name = cust.name _
    Where name.EndsWith("Smith")

Whereクエリ演算子は、Select演算子によって導入されたname範囲変数にのみアクセスできます。Where演算子がcustを参照しようとした場合、コンパイル時エラーが発生しました。

Select クエリ演算子は、範囲変数の名前を明示的に指定する代わりに、匿名型オブジェクト作成式と同じ規則を使用して、範囲変数の名前を推論できます。 例えば次が挙げられます。

Dim custAndOrderNames = _
      From cust In Customers, ord In cust.Orders _
      Select cust.name, ord.ProductName _
        Where name.EndsWith("Smith")

範囲変数の名前が指定されておらず、名前を推論できない場合は、コンパイル時エラーが発生します。 Select クエリ演算子に含まれる式が 1 つだけの場合、その範囲変数の名前を推論できないが、範囲変数が名前のない場合、エラーは発生しません。 例えば次が挙げられます。

Dim custAndOrderNames = _
      From cust In Customers, ord In cust.Orders _
      Select cust.Name & " bought " & ord.ProductName _
        Take 10

範囲変数に名前を割り当てると等しい式を割り当てる間に、 Select クエリ演算子にあいまいさがある場合は、名前の割り当てが推奨されます。 例えば次が挙げられます。

Dim badCustNames = _
      From c In Customers _
        Let name = "John Smith" _
      Select name = c.Name ' Creates a range variable named "name"


Dim goodCustNames = _
      From c In Customers _
        Let name = "John Smith" _
      Select match = (name = c.Name)

Select クエリ演算子の各式は、値として分類する必要があります。 Select クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function Select(selector As Func(Of T, R)) As CR

コード

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Select x, y = x * 10 _
            ...

は、通常、〘

Dim xs() As Integer = ...
Dim zs = _
    xs.Select(Function(x As Integer) New With {x, .y = x * 10})...

個別クエリ演算子

Distinct クエリ演算子は、要素の型を比較して等しいかどうかを判断して、コレクション内の値を個別の値を持つ値のみに制限します。

DistinctQueryOperator
    : LineTerminator? 'Distinct' LineTerminator?
    ;

たとえば、次のクエリについて考えます。

Dim distinctCustomerPrice = _
    From cust In Customers, ord In cust.Orders _
    Select cust.Name, ord.Price _
    Distinct

は、顧客が同じ価格の複数の注文を持っている場合でも、顧客名と注文価格の個別のペアリングごとに 1 つの行のみを返します。 Distinct クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function Distinct() As CT

コード

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Distinct _
            ...

は、通常、〘

Dim xs() As Integer = ...
Dim zs = xs.Distinct()...

"注: Distinct は予約語ではありません。

Where クエリ演算子

Where クエリ演算子は、コレクション内の値を、特定の条件を満たす値に制限します。

WhereQueryOperator
    : LineTerminator? 'Where' LineTerminator? BooleanExpression
    ;

Whereクエリ演算子は、範囲変数値のセットごとに評価されるブール式を受け取ります。式の値が true の場合、値は出力コレクションに表示されます。それ以外の場合、値はスキップされます。 たとえば、クエリ式は次のようになります。

From cust In Customers, ord In Orders _
Where cust.ID = ord.CustomerID _
...

入れ子になったループと同等と考えることができます

For Each cust In Customers
    For Each ord In Orders
            If cust.ID = ord.CustomerID Then
                ...
            End If
    Next ord
Next cust

Where クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function Where(predicate As Func(Of T, B)) As CT

コード

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Where x < 10 _
            ...

は、通常、〘

Dim xs() As Integer = ...
Dim zs = _
    xs.Where(Function(x As Integer) x < 10)...

"注: Where は予約語ではありません。

パーティション クエリ演算子

PartitionQueryOperator
    : LineTerminator? 'Take' LineTerminator? Expression
    | LineTerminator? 'Take' 'While' LineTerminator? BooleanExpression
    | LineTerminator? 'Skip' LineTerminator? Expression
    | LineTerminator? 'Skip' 'While' LineTerminator? BooleanExpression
    ;

Takeクエリ演算子は、コレクションの最初のn要素になります。 While修飾子と共に使用すると、Take演算子は、ブール式を満たすコレクションの最初のn要素になります。 Skip演算子は、コレクションの最初のn要素をスキップし、コレクションの残りの部分を返します。 While修飾子と組み合わせて使用すると、Skip演算子は、ブール式を満たすコレクションの最初のn要素をスキップし、コレクションの残りの部分を返します。 TakeまたはSkipクエリ演算子の式は、値として分類する必要があります。

Take クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function Take(count As N) As CT

Skip クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function Skip(count As N) As CT

Take While クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function TakeWhile(predicate As Func(Of T, B)) As CT

Skip While クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function SkipWhile(predicate As Func(Of T, B)) As CT

コード

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Skip 10 _
            Take 5 _
            Skip While x < 10 _
            Take While x > 5 _
            ...

は、通常、〘

Dim xs() As Integer = ...
Dim zs = _
    xs.Skip(10). _
        Take(5). _
        SkipWhile(Function(x) x < 10). _
        TakeWhile(Function(x) x > 5)...

"注: TakeSkip は予約語ではありません。

クエリ演算子で並べ替え

Order Byクエリ演算子は、範囲変数に表示される値を並べ替えます。

OrderByQueryOperator
    : LineTerminator? 'Order' 'By' LineTerminator? OrderExpressionList
    ;

OrderExpressionList
    : OrderExpression ( Comma OrderExpression )*
    ;

OrderExpression
    : Expression Ordering?
    ;

Ordering
    : 'Ascending' | 'Descending'
    ;

Order Byクエリ演算子は、反復変数の順序付けに使用する必要があるキー値を指定する式を受け取ります。 たとえば、次のクエリでは、価格で並べ替えられた製品が返されます。

Dim productsByPrice = _
    From p In Products _
    Order By p.Price _
    Select p.Name

順序は Ascendingとしてマークできます。その場合、より小さい値が大きい値より前に来る、または Descending。その場合、より大きな値が小さい値の前に来ます。 何も指定されていない場合の順序付けの既定値は Ascending。 たとえば、次のクエリでは、最も高価な製品が最初に価格順に並べ替えられた製品が返されます。

Dim productsByPriceDesc = _
    From p In Products _
    Order By p.Price Descending _
    Select p.Name

Order Byクエリ演算子は、順序付けに複数の式を指定できます。その場合、コレクションは入れ子になった方法で並べ替えられます。 たとえば、次のクエリでは、州別、各州内の市区町村別、および各市区町村内の郵便番号別に顧客を並べ替えています。

Dim customersByLocation = _
    From c In Customers _
    Order By c.State, c.City, c.ZIP _
    Select c.Name, c.State, c.City, c.ZIP

Order By クエリ演算子の式は、値として分類する必要があります。 Order By クエリ演算子は、コレクション型に次のメソッドのいずれかまたは両方が含まれている場合にのみサポートされます。

Function OrderBy(keySelector As Func(Of T, K)) As CT
Function OrderByDescending(keySelector As Func(Of T, K)) As CT

戻り値の型 CT、順序付けられたコレクションである必要があります。 順序付きコレクションは、メソッドの一方または両方を含むコレクション型です。

Function ThenBy(keySelector As Func(Of T, K)) As CT
Function ThenByDescending(keySelector As Func(Of T, K)) As CT

コード

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Order By x Ascending, x Mod 2 Descending _
            ...

は、通常、〘

Dim xs() As Integer = ...
Dim zs = _
    xs.OrderBy(Function(x) x).ThenByDescending(Function(x) x Mod 2)...

"注: クエリ演算子は単に構文を特定のクエリ操作を実装するメソッドにマップするため、順序の保持は言語によって決まるのではなく、演算子自体の実装によって決まります。 これは、ユーザー定義の数値型の加算演算子をオーバーロードする実装では、加算に似た何も実行できないという点で、ユーザー定義演算子によく似ています。 もちろん、予測可能性を維持するために、ユーザーの期待に合わないものを実装することはお勧めしません。

"注: OrderBy は予約語ではありません。

クエリ演算子によるグループ化

Group Byクエリ演算子は、1 つ以上の式に基づいてスコープ内の範囲変数をグループ化し、それらのグループに基づいて新しい範囲変数を生成します。

GroupByQueryOperator
    : LineTerminator? 'Group' ( LineTerminator? ExpressionRangeVariableDeclarationList )?
      LineTerminator? 'By' LineTerminator? ExpressionRangeVariableDeclarationList
      LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

たとえば、次のクエリでは、すべての顧客を State別にグループ化し、各グループの数と平均年齢を計算します。

Dim averageAges = _
    From cust In Customers _
    Group By cust.State _
    Into Count(), Average(cust.Age)

Group By クエリ演算子には、省略可能な Group 句、By 句、および Into 句の 3 つの句があります。 Group句は、Select クエリ演算子と同じ構文と効果を持ちますが、Into句で使用できる範囲変数にのみ影響し、By句には影響しません。 例えば次が挙げられます。

Dim averageAges = _
    From cust In Customers _
    Group cust.Age By cust.State _
    Into Count(), Average(Age)

By句は、グループ化操作でキー値として使用される式範囲変数を宣言します。 Into句を使用すると、By句によって形成された各グループの集計を計算する式範囲変数の宣言が可能になります。 Into句内では、式範囲変数には、集計関数のメソッド呼び出しである式のみを割り当てることができます。 集計関数は、次のいずれかのメソッドのように見えるグループのコレクション型 (必ずしも元のコレクションのコレクション型と同じであるとは限らない) の関数です。

Function _name_() As _type_
Function _name_(selector As Func(Of T, R)) As R

集計関数がデリゲート引数を受け取る場合、呼び出し式には、値として分類する必要がある引数式を指定できます。 引数式では、スコープ内の範囲変数を使用できます。集計関数の呼び出し内では、これらの範囲変数は、コレクション内のすべての値ではなく、形成されるグループ内の値を表します。 たとえば、このセクションの元の例では、 Average 関数は、すべての顧客を合わせるのではなく、州ごとの顧客の年齢の平均を計算します。

すべてのコレクション型は、集計関数が定義 Group と見なされます。パラメーターは受け取らず、単にグループを返します。 コレクション型で提供されるその他の標準集計関数は次のとおりです。

CountLongCount。グループ内の要素の数、またはブール式を満たすグループ内の要素の数を返します。 Count LongCountは、コレクション型に次のいずれかのメソッドが含まれている場合にのみサポートされます。

Function Count() As N
Function Count(selector As Func(Of T, B)) As N
Function LongCount() As N
Function LongCount(selector As Func(Of T, B)) As N

Sum: グループ内のすべての要素に対する式の合計を返します。 Sum は、コレクション型に次のいずれかのメソッドが含まれている場合にのみサポートされます。

Function Sum() As N
Function Sum(selector As Func(Of T, N)) As N

Min グループ内のすべての要素にわたる式の最小値を返します。 Min は、コレクション型に次のいずれかのメソッドが含まれている場合にのみサポートされます。

Function Min() As N
Function Min(selector As Func(Of T, N)) As N

Maxは、グループ内のすべての要素の式の最大値を返します。 Max は、コレクション型に次のいずれかのメソッドが含まれている場合にのみサポートされます。

Function Max() As N
Function Max(selector As Func(Of T, N)) As N

Average: グループ内のすべての要素に対する式の平均を返します。 Average は、コレクション型に次のいずれかのメソッドが含まれている場合にのみサポートされます。

Function Average() As N
Function Average(selector As Func(Of T, N)) As N

Any: グループにメンバーが含まれているかどうか、またはグループ内の任意の要素に対してブール式が true かどうかを決定します。 Any はブール式で使用できる値を返し、コレクション型にいずれかのメソッドが含まれている場合にのみサポートされます。

Function Any() As B
Function Any(predicate As Func(Of T, B)) As B

All: ブール式がグループ内のすべての要素に対して true かどうかを決定します。 All はブール式で使用できる値を返し、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function All(predicate As Func(Of T, B)) As B

Group Byクエリ演算子の後、スコープ内の以前の範囲変数は非表示になり、By句と Into 句によって導入された範囲変数を使用できます。 Group By クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function GroupBy(keySelector As Func(Of T, K), _
                      resultSelector As Func(Of K, CT, R)) As CR

Group句の範囲変数宣言は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function GroupBy(keySelector As Func(Of T, K), _
                      elementSelector As Func(Of T, S), _
                      resultSelector As Func(Of K, CS, R)) As CR

コード

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Group y = x * 10, z = x / 10 By evenOdd = x Mod 2 _
            Into Sum(y), Average(z) _
            ...

は、通常、〘

Dim xs() As Integer = ...
Dim zs = _
    xs.GroupBy( _
        Function(x As Integer) x Mod 2, _
        Function(x As Integer) New With {.y = x * 10, .z = x / 10}, _
        Function(evenOdd, group) New With { _
            evenOdd, _
            .Sum = group.Sum(Function(e) e.y), _
            .Average = group.Average(Function(e) e.z)})...

Note.GroupByInto は予約語ではありません。

集計クエリ演算子

Aggregate クエリ演算子は、既に形成されているグループを集計できる点を除き、Group By演算子と同様の関数を実行します。 グループは既に形成されているため、Aggregateクエリ演算子のInto句ではスコープ内の範囲変数は非表示になりません (この方法では、AggregateLetに似ていますが、Group BySelectに似ています)。

AggregateQueryOperator
    : LineTerminator? 'Aggregate' LineTerminator? CollectionRangeVariableDeclaration QueryOperator*
      LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

たとえば、次のクエリは、ワシントンの顧客によって行われたすべての注文の合計を集計します。

Dim orderTotals = _
    From cust In Customers _
    Where cust.State = "WA" _
    Aggregate order In cust.Orders _
    Into Sum(order.Total)

このクエリの結果は、要素型が匿名型で、custという名前のプロパティがCustomerとして型指定され、Integerとして型指定されたプロパティSum持つコレクションです。

Group Byとは異なり、Aggregate句とInto句の間に追加のクエリ演算子を配置できます。 Aggregate句と Into 句の末尾の間では、スコープ内のすべての範囲変数 (Aggregate 句で宣言されているものも含む) を使用できます。 たとえば、次のクエリは、2006 年より前にワシントンで顧客が行ったすべての注文の合計を集計します。

Dim orderTotals = _
    From cust In Customers _
    Where cust.State = "WA" _
    Aggregate order In cust.Orders _
    Where order.Date <= #01/01/2006# _
    Into Sum = Sum(order.Total)

Aggregate演算子を使用して、クエリ式を開始することもできます。 この場合、クエリ式の結果は、 Into 句によって計算される単一の値になります。 たとえば、次のクエリでは、2006 年 1 月 1 日より前のすべての注文合計の合計が計算されます。

Dim ordersTotal = _
    Aggregate order In Orders _
    Where order.Date <= #01/01/2006# _
    Into Sum(order.Total)

クエリの結果は、単一の Integer 値になります。 Aggregateクエリ演算子は常に使用できます (ただし、式を有効にするには集計関数も使用できる必要があります)。 コード

Dim xs() As Integer = ...
Dim zs = _
    Aggregate x In xs _
    Where x < 5 _
    Into Sum()

は、通常、〘

Dim xs() As Integer = ...
Dim zs = _
    xs.Where(Function(x) x < 5).Sum()

"注:  AggregateInto は予約語ではありません。

グループ結合クエリ演算子

Group Join クエリ演算子は、JoinおよびGroup Byクエリ演算子の関数を 1 つの演算子に結合します。 Group Join は、要素から抽出された一致するキーに基づいて 2 つのコレクションを結合し、結合の左側の特定の要素と一致する結合の右側にあるすべての要素をグループ化します。 したがって、演算子は階層的な結果のセットを生成します。

GroupJoinQueryOperator
    : LineTerminator? 'Group' 'Join' LineTerminator? CollectionRangeVariableDeclaration
      JoinOrGroupJoinQueryOperator? LineTerminator? 'On' LineTerminator? JoinConditionList
      LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

たとえば、次のクエリでは、1 人の顧客の名前、すべての注文のグループ、およびそれらのすべての注文の合計金額を含む要素が生成されます。

Dim custsWithOrders = _
    From cust In Customers _
    Group Join order In Orders On cust.ID Equals order.CustomerID _ 
    Into Orders = Group, OrdersTotal = Sum(order.Total) _
    Select cust.Name, Orders, OrdersTotal

クエリの結果は、要素型が匿名型のコレクションで、 NameStringとして型指定、 Orders 要素型が Orderのコレクションとして型指定され、 OrdersTotalInteger として型指定されます。 Group Join クエリ演算子は、コレクション型にメソッドが含まれている場合にのみサポートされます。

Function GroupJoin(inner As CS, _
                         outerSelector As Func(Of T, K), _
                         innerSelector As Func(Of S, K), _
                         resultSelector As Func(Of T, CS, R)) As CR

コード

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs _
            Group Join y in ys On x Equals y _
            Into g = Group _
            ...

は、通常、〘

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = _
    xs.GroupJoin( _
        ys, _
        Function(x As Integer) x, _
        Function(y As Integer) y, _
        Function(x, group) New With {x, .g = group})...

Note.GroupJoinInto は予約語ではありません。

条件式

条件 If 式は式をテストし、値を返します。

ConditionalExpression
    : 'If' OpenParenthesis BooleanExpression Comma Expression Comma Expression CloseParenthesis
    | 'If' OpenParenthesis Expression Comma Expression CloseParenthesis
    ;

ただし、 IIF ランタイム関数とは異なり、条件式は必要に応じてそのオペランドのみを評価します。 したがって、たとえば、If(c Is Nothing, c.Name, "Unknown")の値がcされている場合、式Nothingは例外をスローしません。 条件式には 2 つの形式があります。1 つは 2 つのオペランドを受け取り、1 つは 3 つのオペランドを受け取ります。

3 つのオペランドが指定されている場合、3 つの式はすべて値として分類する必要があり、最初のオペランドはブール式である必要があります。 式の結果が true の場合、2 番目の式は演算子の結果になります。それ以外の場合、3 番目の式は演算子の結果になります。 式の結果型は、2 番目の式と 3 番目の式の型の間の主要な型です。 主要な型がない場合は、コンパイル時エラーが発生します。

2 つのオペランドが指定されている場合、両方のオペランドを値として分類し、最初のオペランドは参照型または null 許容値型である必要があります。 その後、式 If(x, y) は、式が If(x IsNot Nothing, x, y)されたかのように評価されます。ただし、2 つの例外があります。 最初に、最初の式は 1 回だけ評価され、2 番目のオペランドの型が null 非許容値型で、最初のオペランドの型が 1 番目のオペランドである場合、式の結果型の主要な型を決定するときに、最初のオペランドの型から ? が削除されます。 例えば次が挙げられます。

Module Test
    Sub Main()
        Dim x?, y As Integer
        Dim a?, b As Long

        a = If(x, a)        ' Result type: Long?
        y = If(x, 0)        ' Result type: Integer
    End Sub
End Module

どちらの形式の式でも、オペランドが Nothingされている場合、その型は主な型を決定するために使用されません。 式 If(<expression>, Nothing, Nothing)の場合、主型は Objectと見なされます。

XML リテラル式

XML リテラル式は、XML (拡張マークアップ言語) 1.0 の値を表します。

XMLLiteralExpression
    : XMLDocument
    | XMLElement
    | XMLProcessingInstruction
    | XMLComment
    | XMLCDATASection
    ;

XML リテラル式の結果は、 System.Xml.Linq 名前空間の型の 1 つとして型指定された値になります。 その名前空間内の型を使用できない場合、XML リテラル式によってコンパイル時エラーが発生します。 値は、XML リテラル式から変換されたコンストラクター呼び出しによって生成されます。 たとえば、次のコードがあります。

Dim book As System.Xml.Linq.XElement = _
    <book title="My book"></book>

は、次のコードとほぼ同じです。

Dim book As System.Xml.Linq.XElement = _
    New System.Xml.Linq.XElement( _
        "book", _
        New System.Xml.Linq.XAttribute("title", "My book"))

XML リテラル式は、XML ドキュメント、XML 要素、XML 処理命令、XML コメント、または CDATA セクションの形式をとることができます。

"注: この仕様には、Visual Basic 言語の動作を記述するのに十分な XML の説明のみが含まれています。 XML の詳細については、 http://www.w3.org/TR/REC-xml/を参照してください。

字句規則

XMLCharacter
    : '<Unicode tab character (0x0009)>'
    | '<Unicode linefeed character (0x000A)>'
    | '<Unicode carriage return character (0x000D)>'
    | '<Unicode characters 0x0020 - 0xD7FF>'
    | '<Unicode characters 0xE000 - 0xFFFD>'
    | '<Unicode characters 0x10000 - 0x10FFFF>'
    ;

XMLString
    : XMLCharacter+
    ;

XMLWhitespace
    : XMLWhitespaceCharacter+
    ;

XMLWhitespaceCharacter
    : '<Unicode carriage return character (0x000D)>'
    | '<Unicode linefeed character (0x000A)>'
    | '<Unicode space character (0x0020)>'
    | '<Unicode tab character (0x0009)>'
    ;

XMLNameCharacter
    : XMLLetter
    | XMLDigit
    | '.'
    | '-'
    | '_'
    | ':'
    | XMLCombiningCharacter
    | XMLExtender
    ;

XMLNameStartCharacter
    : XMLLetter
    | '_'
    | ':'
    ;

XMLName
    : XMLNameStartCharacter XMLNameCharacter*
    ;

XMLLetter
    : '<Unicode character as defined in the Letter production of the XML 1.0 specification>'
    ;

XMLDigit
    : '<Unicode character as defined in the Digit production of the XML 1.0 specification>'
    ;

XMLCombiningCharacter
    : '<Unicode character as defined in the CombiningChar production of the XML 1.0 specification>'
    ;

XMLExtender
    : '<Unicode character as defined in the Extender production of the XML 1.0 specification>'
    ;

XML リテラル式は、通常の Visual Basic コードの字句規則ではなく、XML の字句規則を使用して解釈されます。 一般に、2 つのルール セットは次の点で異なります。

  • 空白は XML では重要です。 その結果、XML リテラル式の文法では、空白が許可される場所が明示的に示されます。 空白は、要素内の文字データのコンテキストで発生する場合を除き、保持されません。 例えば次が挙げられます。

    ' The following element preserves no whitespace
    Dim e1 = _
        <customer>
            <name>Bob</>
        </>
    
    ' The following element preserves all of the whitespace
    Dim e2 = _
        <customer>
            Bob
        </>
    
  • XML 行末の空白は、XML 仕様に従って正規化されます。

  • XML では大文字と小文字が区別されます。 キーワードは大文字と小文字が正確に一致する必要があります。そうしないと、コンパイル時エラーが発生します。

  • 行終端記号は、XML では空白と見なされます。 その結果、XML リテラル式では行連結文字は必要ありません。

  • XML では、全角文字は使用できません。 全角文字を使用すると、コンパイル時エラーが発生します。

埋め込み式

XML リテラル式には 、埋め込み式を含めることができます。 埋め込み式は、埋め込み式の場所で 1 つ以上の値を入力するために評価および使用される Visual Basic 式です。

XMLEmbeddedExpression
    : '<' '%' '=' LineTerminator? Expression LineTerminator? '%' '>'
    ;

たとえば、次のコードでは、文字列 John Smith を XML 要素の値として配置します。

Dim name as String = "John Smith"
Dim element As System.Xml.Linq.XElement = <customer><%= name %></customer>

式は、さまざまなコンテキストに埋め込むことができます。 たとえば、次のコードでは、 customerという名前の要素が生成されます。

Dim name As String = "customer"
Dim element As System.Xml.Linq.XElement = <<%= name %>>John Smith</>

埋め込み式を使用できる各コンテキストは、受け入れられる型を指定します。 埋め込み式の式部分のコンテキスト内では、Visual Basic コードの通常の字句規則が引き続き適用されます。たとえば、行の継続を使用する必要があります。

' Visual Basic expression uses line continuation, XML does not
Dim element As System.Xml.Linq.XElement = _
    <<%= name & _
          name %>>John 
                     Smith</>

XML ドキュメント

XMLDocument
    : XMLDocumentPrologue XMLMisc* XMLDocumentBody XMLMisc*
    ;

XMLDocumentPrologue
    : '<' '?' 'xml' XMLVersion XMLEncoding? XMLStandalone? XMLWhitespace? '?' '>'
    ;

XMLVersion
    : XMLWhitespace 'version' XMLWhitespace? '=' XMLWhitespace? XMLVersionNumberValue
    ;

XMLVersionNumberValue
    : SingleQuoteCharacter '1' '.' '0' SingleQuoteCharacter
    | DoubleQuoteCharacter '1' '.' '0' DoubleQuoteCharacter
    ;

XMLEncoding
    : XMLWhitespace 'encoding' XMLWhitespace? '=' XMLWhitespace? XMLEncodingNameValue
    ;

XMLEncodingNameValue
    : SingleQuoteCharacter XMLEncodingName SingleQuoteCharacter
    | DoubleQuoteCharacter XMLEncodingName DoubleQuoteCharacter
    ;

XMLEncodingName
    : XMLLatinAlphaCharacter XMLEncodingNameCharacter*
    ;

XMLEncodingNameCharacter
    : XMLUnderscoreCharacter
    | XMLLatinAlphaCharacter
    | XMLNumericCharacter
    | XMLPeriodCharacter
    | XMLDashCharacter
    ;

XMLLatinAlphaCharacter
    : '<Unicode Latin alphabetic character (0x0041-0x005a, 0x0061-0x007a)>'
    ;

XMLNumericCharacter
    : '<Unicode digit character (0x0030-0x0039)>'
    ;

XMLHexNumericCharacter
    : XMLNumericCharacter
    | '<Unicode Latin hex alphabetic character (0x0041-0x0046, 0x0061-0x0066)>'
    ;

XMLPeriodCharacter
    : '<Unicode period character (0x002e)>'
    ;

XMLUnderscoreCharacter
    : '<Unicode underscore character (0x005f)>'
    ;

XMLDashCharacter
    : '<Unicode dash character (0x002d)>'
    ;

XMLStandalone
    : XMLWhitespace 'standalone' XMLWhitespace? '=' XMLWhitespace? XMLYesNoValue
    ;

XMLYesNoValue
    : SingleQuoteCharacter XMLYesNo SingleQuoteCharacter
    | DoubleQuoteCharacter XMLYesNo DoubleQuoteCharacter
    ;

XMLYesNo
    : 'yes'
    | 'no'
    ;

XMLMisc
    : XMLComment
    | XMLProcessingInstruction
    | XMLWhitespace
    ;

XMLDocumentBody
    : XMLElement
    | XMLEmbeddedExpression
    ;

XML ドキュメントは、 System.Xml.Linq.XDocumentとして型指定された値になります。 XML 1.0 仕様とは異なり、XML ドキュメントのプロローグを指定するには、XML リテラル式の XML ドキュメントが必要です。XML ドキュメント プロローグのない XML リテラル式は、個々のエンティティとして解釈されます。 例えば次が挙げられます。

Dim doc As System.Xml.Linq.XDocument = _
    <?xml version="1.0"?>
    <?instruction?>
    <customer>Bob</>

Dim pi As System.Xml.Linq.XProcessingInstruction = _
    <?instruction?>

XML ドキュメントには、任意の型を使用できる埋め込み式を含めることができます。ただし、実行時には、オブジェクトは XDocument コンストラクターの要件を満たす必要があります。または、実行時エラーが発生します。

通常の XML とは異なり、XML ドキュメント式は DTD (ドキュメント型宣言) をサポートしていません。 また、Xml リテラル式のエンコードはソース ファイル自体のエンコードと常に同じであるため、エンコード属性を指定した場合は無視されます。

"注: エンコード属性は無視されますが、有効な Xml 1.0 ドキュメントをソース コードに含める機能を維持するために有効な属性です。

XML 要素

XMLElement
    : XMLEmptyElement
    | XMLElementStart XMLContent XMLElementEnd
    ;

XMLEmptyElement
    : '<' XMLQualifiedNameOrExpression XMLAttribute* XMLWhitespace? '/' '>'
    ;

XMLElementStart
    : '<' XMLQualifiedNameOrExpression XMLAttribute* XMLWhitespace? '>'
    ;

XMLElementEnd
    : '<' '/' '>'
    | '<' '/' XMLQualifiedName XMLWhitespace? '>'
    ;

XMLContent
    : XMLCharacterData? ( XMLNestedContent XMLCharacterData? )+
    ;

XMLCharacterData
    : '<Any XMLCharacterDataString that does not contain the string "]]>">'
    ;

XMLCharacterDataString
    : '<Any Unicode character except < or &>'+
    ;

XMLNestedContent
    : XMLElement
    | XMLReference
    | XMLCDATASection
    | XMLProcessingInstruction
    | XMLComment
    | XMLEmbeddedExpression
    ;

XMLAttribute
    : XMLWhitespace XMLAttributeName XMLWhitespace? '=' XMLWhitespace? XMLAttributeValue
    | XMLWhitespace XMLEmbeddedExpression
    ;

XMLAttributeName
    : XMLQualifiedNameOrExpression
    | XMLNamespaceAttributeName
    ;

XMLAttributeValue
    : DoubleQuoteCharacter XMLAttributeDoubleQuoteValueCharacter* DoubleQuoteCharacter
    | SingleQuoteCharacter XMLAttributeSingleQuoteValueCharacter* SingleQuoteCharacter
    | XMLEmbeddedExpression
    ;

XMLAttributeDoubleQuoteValueCharacter
    : '<Any XMLCharacter except <, &, or DoubleQuoteCharacter>'
    | XMLReference
    ;

XMLAttributeSingleQuoteValueCharacter
    : '<Any XMLCharacter except <, &, or SingleQuoteCharacter>'
    | XMLReference
    ;

XMLReference
    : XMLEntityReference
    | XMLCharacterReference
    ;

XMLEntityReference
    : '&' XMLEntityName ';'
    ;

XMLEntityName
    : 'lt' | 'gt' | 'amp' | 'apos' | 'quot'
    ;

XMLCharacterReference
    : '&' '#' XMLNumericCharacter+ ';'
    | '&' '#' 'x' XMLHexNumericCharacter+ ';'
    ;

XML 要素は、 System.Xml.Linq.XElementとして型指定された値になります。 通常の XML とは異なり、XML 要素は終了タグ内の名前を省略でき、現在の入れ子になった要素は閉じられます。 例えば次が挙げられます。

Dim name = <name>Bob</>

XML 要素の属性宣言は、 System.Xml.Linq.XAttributeとして型指定された値になります。 属性値は、XML 仕様に従って正規化されます。 属性の値が Nothing 場合、属性は作成されないため、属性値式を Nothingチェックする必要はありません。 例えば次が挙げられます。

Dim expr = Nothing

' Throws null argument exception
Dim direct = New System.Xml.Linq.XElement( _
    "Name", _
    New System.Xml.Linq.XAttribute("Length", expr))

' Doesn't throw exception, the result is <Name/>
Dim literal = <Name Length=<%= expr %>/>

XML 要素と属性には、次の場所に入れ子になった式を含めることができます。

要素の名前。この場合、埋め込み式は、 System.Xml.Linq.XNameに暗黙的に変換できる型の値である必要があります。 例えば次が挙げられます。

Dim name = <<%= "name" %>>Bob</>

要素の属性の名前。その場合、埋め込み式は System.Xml.Linq.XNameに暗黙的に変換できる型の値である必要があります。 例えば次が挙げられます。

Dim name = <name <%= "length" %>="3">Bob</>

要素の属性の値。その場合、埋め込み式は任意の型の値にすることができます。 例えば次が挙げられます。

Dim name = <name length=<%= 3 %>>Bob</>

要素の属性。この場合、埋め込み式は任意の型の値にすることができます。 例えば次が挙げられます。

Dim name = <name <%= new XAttribute("length", 3) %>>Bob</>

要素の内容。この場合、埋め込み式は任意の型の値にすることができます。 例えば次が挙げられます。

Dim name = <name><%= "Bob" %></>

埋め込み式の型が Object()場合、配列はパラメーターとして XElement コンストラクターに渡されます。

XML 名前空間

XML 要素には、XML 名前空間 1.0 仕様で定義されている XML 名前空間宣言を含めることができます。

XMLNamespaceAttributeName
    : XMLPrefixedNamespaceAttributeName
    | XMLDefaultNamespaceAttributeName
    ;

XMLPrefixedNamespaceAttributeName
    : 'xmlns' ':' XMLNamespaceName
    ;

XMLDefaultNamespaceAttributeName
    : 'xmlns'
    ;

XMLNamespaceName
    : XMLNamespaceNameStartCharacter XMLNamespaceNameCharacter*
    ;

XMLNamespaceNameStartCharacter
    : '<Any XMLNameCharacter except :>'
    ;

XMLNamespaceNameCharacter
    : XMLLetter
    | '_'
    ;

XMLQualifiedNameOrExpression
    : XMLQualifiedName
    | XMLEmbeddedExpression
    ;

XMLQualifiedName
    : XMLPrefixedName
    | XMLUnprefixedName
    ;

XMLPrefixedName
    : XMLNamespaceName ':' XMLNamespaceName
    ;

XMLUnprefixedName
    : XMLNamespaceName
    ;

xmlおよびxmlnsの定義に関する制限が適用され、コンパイル時エラーが発生します。 XML 名前空間宣言には、その値の埋め込み式を含めることはできません。指定する値は空でない文字列リテラルである必要があります。 例えば次が挙げられます。

' Declares a valid namespace
Dim customer = <db:customer xmlns:db="http://example.org/database">Bob</>

' Error: xmlns cannot be re-defined
Dim bad1 = <elem xmlns:xmlns="http://example.org/namespace"/>

' Error: cannot have an embedded expression
Dim bad2 = <elem xmlns:db=<%= "http://example.org/database" %>>Bob</>

"注: この仕様には、Visual Basic 言語の動作を記述するのに十分な XML 名前空間の説明のみが含まれています。 XML 名前空間の詳細については、 http://www.w3.org/TR/REC-xml-names/を参照してください。

XML 要素名と属性名は、名前空間名を使用して修飾できます。 名前空間は通常の XML と同様にバインドされます。ただし、ファイル レベルで宣言された名前空間のインポートは、宣言を囲むコンテキストで宣言されていると見なされ、それ自体はコンパイル環境で宣言された名前空間のインポートで囲まれています。 名前空間名が見つからない場合は、コンパイル時エラーが発生します。 例えば次が挙げられます。

Imports System.Xml.Linq
Imports <xmlns:db="http://example.org/database">

Module Test
    Sub Main()
        ' Binds to the imported namespace above.
        Dim c1 = <db:customer>Bob</>

        ' Binds to the namespace declaration in the element
        Dim c2 = _
            <db:customer xmlns:db="http://example.org/database-other">Mary</>

        ' Binds to the inner namespace declaration
        Dim c3 = _
            <database xmlns:db="http://example.org/database-one">
                <db:customer xmlns:db="http://example.org/database-two">Joe</>
            </>

        ' Error: namespace db2 cannot be found
        Dim c4 = _
            <db2:customer>Jim</>
    End Sub
End Module

要素で宣言された XML 名前空間は、埋め込み式内の XML リテラルには適用されません。 例えば次が挙げられます。

' Error: Namespace prefix 'db' is not declared
Dim customer = _
    <db:customer xmlns:db="http://example.org/database">
        <%= <db:customer>Bob</> %>
    </>

"注: これは、関数呼び出しを含め、埋め込み式に任意の値を指定できるためです。 関数呼び出しに XML リテラル式が含まれている場合、プログラマが XML 名前空間が適用されるか無視されるかは明確ではありません。

XML 処理命令

XML 処理命令は、 System.Xml.Linq.XProcessingInstructionとして型指定された値になります。 XML 処理命令は、処理命令内の有効な構文であるため、埋め込み式を含めることはできません。

XMLProcessingInstruction
    : '<' '?' XMLProcessingTarget ( XMLWhitespace XMLProcessingValue? )? '?' '>'
    ;

XMLProcessingTarget
    : '<Any XMLName except a casing permutation of the string "xml">'
    ;

XMLProcessingValue
    : '<Any XMLString that does not contain a question-mark followed by ">">'
    ;

XML コメント

XML コメントは、 System.Xml.Linq.XCommentとして型指定された値になります。 XML コメントは、コメント内の有効な構文であるため、埋め込み式を含めることはできません。

XMLComment
    : '<' '!' '-' '-' XMLCommentCharacter* '-' '-' '>'
    ;

XMLCommentCharacter
    : '<Any XMLCharacter except dash (0x002D)>'
    | '-' '<Any XMLCharacter except dash (0x002D)>'
    ;

CDATA セクション

CDATA セクションは、 System.Xml.Linq.XCDataとして型指定された値になります。 CDATA セクションには、CDATA セクション内の有効な構文であるため、埋め込み式を含めることはできません。

XMLCDATASection
    : '<' '!' ( 'CDATA' '[' XMLCDATASectionString? ']' )? '>'
    ;

XMLCDATASectionString
    : '<Any XMLString that does not contain the string "]]>">'
    ;

XML メンバー アクセス式

XML メンバー アクセス式は、XML 値のメンバーにアクセスします。

XMLMemberAccessExpression
    : Expression '.' LineTerminator? '<' XMLQualifiedName '>'
    | Expression '.' LineTerminator? '@' LineTerminator? '<' XMLQualifiedName '>'
    | Expression '.' LineTerminator? '@' LineTerminator? IdentifierOrKeyword
    | Expression '.' '.' '.' LineTerminator? '<' XMLQualifiedName '>'
    ;

XML メンバー アクセス式には、次の 3 種類があります。

  • XML 名が 1 つのドットの後に続く要素アクセス。 例えば次が挙げられます。

    Dim customer = _
        <customer>
            <name>Bob</>
        </>
    Dim customerName = customer.<name>.Value
    

    要素アクセスは関数にマップされます。

    Function Elements(name As System.Xml.Linq.XName) As _
        System.Collections.Generic.IEnumerable(Of _
            System.Xml.Linq.XNode)
    

    したがって、上記の例は次のようになります。

    Dim customerName = customer.Elements("name").Value
    
  • Visual Basic 識別子がドットとアット マークの後に続く属性アクセス、または XML 名がドットとアット マークの後に続く属性アクセス。 例えば次が挙げられます。

    Dim customer = <customer age="30"/>
    Dim customerAge = customer.@age
    

    属性アクセスは関数にマップされます。

    Function AttributeValue(name As System.Xml.Linq.XName) as String
    

    したがって、上記の例は次のようになります。

    Dim customerAge = customer.AttributeValue("age")
    

    "注: AttributeValue拡張メソッド (および関連する拡張プロパティ Value) は、現在、どのアセンブリでも定義されていません。 拡張メンバーが必要な場合は、生成されるアセンブリで自動的に定義されます。

  • XML 名が 3 つのドットに続く降順アクセス。 例えば次が挙げられます。

    Dim company = _
        <company>
            <customers>
                <customer>Bob</>
                <customer>Mary</>
                <customer>Joe</>
            </>
        </>
    Dim customers = company...<customer>
    

    降順アクセスは関数にマップされます。

    Function Descendents(name As System.Xml.Linq.XName) As _
        System.Collections.Generic.IEnumerable(Of _
            System.Xml.Linq.XElement)
    

    したがって、上記の例は次のようになります。

    Dim customers = company.Descendants("customer")
    

XML メンバー アクセス式の基本式は値であり、次の型である必要があります。

  • 要素または子孫がアクセスする場合、 System.Xml.Linq.XContainer または派生型、または System.Collections.Generic.IEnumerable(Of T) または派生型 ( TSystem.Xml.Linq.XContainer または派生型である場合)。

  • 属性がアクセスする場合、 System.Xml.Linq.XElement または派生型、または System.Collections.Generic.IEnumerable(Of T) または派生型 ( TSystem.Xml.Linq.XElement または派生型である場合)。

XML メンバー アクセス式の名前を空にすることはできません。 インポートによって定義された任意の名前空間を使用して、名前空間を修飾できます。 例えば次が挙げられます。

Imports <xmlns:db="http://example.org/database">

Module Test
    Sub Main()
        Dim customer = _
            <db:customer>
                <db:name>Bob</>
            </>
        Dim name = customer.<db:name>
    End Sub
End Module

XML メンバー アクセス式のドットの後、または山かっこと名前の間の空白は使用できません。 例えば次が挙げられます。

Dim customer = _
    <customer age="30">
        <name>Bob</>
    </>
' All the following are error cases
Dim age = customer.@ age
Dim name = customer.< name >
Dim names = customer...< name >

System.Xml.Linq名前空間の型を使用できない場合、XML メンバー アクセス式によってコンパイル時エラーが発生します。

Await 演算子

await 演算子は、非同期メソッドに関連しています。非同期メソッドのセクションで説明 されています

AwaitOperatorExpression
    : 'Await' Expression
    ;

Awaitは、即時に囲むメソッドまたはラムダ式にAsync修飾子があり、そのAsync修飾子の後にAwaitが表示される場合は予約語です。他の場所では予約されません。 プリプロセッサ ディレクティブでも予約されません。 await 演算子は、予約語であるメソッドまたはラムダ式の本体でのみ使用できます。 すぐに囲むメソッドまたはラムダ内では、await 式は、 Catch または Finally ブロックの本体内、 SyncLock ステートメントの本体内、またはクエリ式内では発生しない可能性があります。

await 演算子は、値として分類する必要があり、その型が 待機可能な 型または Objectである必要がある単一の式を受け取ります。 型が Object の場合、すべての処理は実行時まで延期されます。 次のすべてが当てはまる場合、 C 型は待機可能と言われます。

  • Cには、引数がなく、何らかの型Eを返すGetAwaiterという名前のアクセス可能なインスタンスまたは拡張メソッドが含まれています。

  • E には、引数を受け取り、ブール型を持つ IsCompleted という名前の読み取り可能なインスタンスまたは拡張プロパティが含まれています。

  • E には、引数を受け取っていない GetResult という名前のアクセス可能なインスタンスまたは拡張メソッドが含まれています。

  • E は、 System.Runtime.CompilerServices.INotifyCompletion または ICriticalNotifyCompletionを実装します。

GetResultSubの場合、await 式は void として分類されます。 それ以外の場合、await 式は値として分類され、その型は GetResult メソッドの戻り値の型になります。

待機可能なクラスの例を次に示します。

Class MyTask(Of T)
    Function GetAwaiter() As MyTaskAwaiter(Of T)
        Return New MyTaskAwaiter With {.m_Task = Me}
    End Function

    ...
End Class

Structure MyTaskAwaiter(Of T)
    Implements INotifyCompletion

    Friend m_Task As MyTask(Of T)

    ReadOnly Property IsCompleted As Boolean
        Get
            Return m_Task.IsCompleted
        End Get
    End Property

    Sub OnCompleted(r As Action) Implements INotifyCompletion.OnCompleted
        ' r is the "resumptionDelegate"
        Dim sc = SynchronizationContext.Current
        If sc Is Nothing Then
            m_Task.ContinueWith(Sub() r())
        Else
            m_Task.ContinueWith(Sub() sc.Post(Sub() r(), Nothing))
        End If
    End Sub

    Function GetResult() As T
        If m_Task.IsCanceled Then Throw New TaskCanceledException(m_Task)
        If m_Task.IsFaulted Then Throw m_Task.Exception.InnerException
        Return m_Task.Result
    End Function
End Structure

"注: ライブラリ作成者は、OnCompleted自体が呼び出されたのと同じSynchronizationContextで継続デリゲートを呼び出すパターンに従うことをお勧めします。 また、再開デリゲートは、スタック オーバーフローにつながる可能性があるため、 OnCompleted メソッド内で同期的に実行しないでください。代わりに、後続の実行のためにデリゲートをキューに入れる必要があります。

制御フローが Await 演算子に到達すると、動作は次のようになります。

  1. await オペランドの GetAwaiter メソッドが呼び出されます。 この呼び出しの結果は、 awaiter と呼びます。

  2. awaiter の IsCompleted プロパティが取得されます。 結果が true の場合:

    1. awaiter の GetResult メソッドが呼び出されます。 GetResultが関数であった場合、await 式の値はこの関数の戻り値になります。
  3. IsCompleted プロパティが true でない場合:

    1. awaiter でICriticalNotifyCompletion.UnsafeOnCompletedが呼び出されるか (awaiter の型EICriticalNotifyCompletionが実装されている場合)、またはINotifyCompletion.OnCompleted (それ以外の場合)。 どちらの場合も、非同期メソッドの現在のインスタンスに関連付けられている 再開デリゲート を渡します。

    2. 現在の非同期メソッド インスタンスの制御ポイントが中断され、現在の 呼び出し元 (セクション 非同期メソッドで定義) で制御フローが再開されます。

    3. 後で再開デリゲートが呼び出された場合、

      1. 再開デリゲートは、最初に、OnCompletedが呼び出された時点の状態にSystem.Threading.Thread.CurrentThread.ExecutionContext復元します。
      2. その後、非同期メソッド インスタンスの制御ポイントで制御フローを再開します (「 非同期メソッド」セクションを参照)
      3. ここで、上の 2.1 のように、awaiter の GetResult メソッドを呼び出します。

await オペランドに Object 型がある場合、この動作はランタイムまで延期されます。

  • 手順 1 は、引数なしで GetAwaiter() を呼び出すことによって実現されます。したがって、実行時に省略可能なパラメーターを受け取るインスタンス メソッドにバインドできます。
  • 手順 2 は、引数なしで IsCompleted() プロパティを取得し、ブール型への組み込み変換を試みることによって実現されます。
  • 手順 3.a は、 TryCast(awaiter, ICriticalNotifyCompletion)を試みることで実行され、失敗した場合は DirectCast(awaiter, INotifyCompletion)

3.a で渡された再開デリゲートは、1 回だけ呼び出すことができます。 複数回呼び出された場合、動作は未定義です。