次の方法で共有


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

実際には、オーバーロードの解決を決定するための規則は、指定された実際の引数に "最も近い" オーバーロードを見つけることを目的としています。 パラメーター型が引数の型と一致するメソッドがある場合、そのメソッドは明らかに最も近いです。 そのため、すべてのパラメーター型が他のメソッドのパラメーター型よりも狭い (または同じ) 場合、1 つのメソッドは別のメソッドよりも近くなります。 どちらのメソッドのパラメーターも他のパラメーターよりも狭い場合、引数に近いメソッドを判断する方法はありません。

"注: オーバーロードの解決では、メソッドの予期される戻り値の型は考慮されません。

また、名前付きパラメーター構文のため、実際のパラメーターと仮パラメーターの順序が同じにならない場合があることにも注意してください。

メソッド グループの場合、引数リストのグループ内で最も適用可能なメソッドは、次の手順を使用して決定されます。 特定のステップを適用した後、メンバーがセットに残っていない場合は、コンパイル時エラーが発生します。 セット内にメンバーが 1 つだけ残っている場合は、そのメンバーが最も適用可能なメンバーになります。 手順は次のとおりです。

  1. 最初に、型引数が指定されていない場合は、型パラメーターを持つメソッドに型推論を適用します。 メソッドの型推論が成功した場合は、その特定のメソッドに対して推論された型引数が使用されます。 メソッドの型推論が失敗した場合、そのメソッドはセットから削除されます。

  2. 次に、アクセスできない、または適用できないセットからすべてのメンバーを削除します ( 引数リストへの適用可能性セクション) を引数リストに追加します。

  3. 次に、1 つ以上の引数が AddressOf またはラムダ式である場合は、次のような各引数の デリゲート緩和レベル を計算します。 Nで最も低い (最も低い) デリゲート緩和レベルがMの最も低いデリゲート緩和レベルよりも悪い場合は、セットからNを排除します。 デリゲート緩和レベルは次のとおりです。

    1. エラー デリゲート緩和レベル -- AddressOf またはラムダをデリゲート型に変換できない場合。

    2. 戻り値の型またはパラメーターのデリゲートの緩和を縮小する -- 引数が AddressOf または宣言された型のラムダで、その戻り値の型からデリゲートの戻り値の型への変換が縮小されている場合、または引数が通常のラムダであり、その戻り式からデリゲートの戻り値の型への変換が縮小されている場合、 または、引数が非同期ラムダであり、デリゲートの戻り値の型が Task(Of T) され、その戻り値の式のいずれかから T への変換が縮小されている場合、または引数が反復子ラムダであり、デリゲートの戻り値の型が IEnumerator(Of T) または IEnumerable(Of T) の場合、その yield オペランドから T への変換は縮小されます。

    3. デリゲート型がSystem.DelegateまたはSystem.MultiCastDelegateまたはSystem.Objectの場合、デリゲートの緩和をシグネチャなしでデリゲートに拡大します。

    4. 戻り値の削除またはデリゲートの緩和 -- 引数が AddressOf または宣言された戻り値の型を持つラムダで、デリゲート型に戻り値の型がない場合、または引数が 1 つ以上の戻り値の式を持つラムダで、デリゲート型に戻り値の型がない場合、または引数が AddressOf またはラムダで、デリゲート型にパラメーターがある場合。

    5. 戻り値の型の拡大デリゲートの緩和 -- 引数が AddressOf または宣言された戻り値の型を持つラムダであり、その戻り値の型からデリゲートの戻り値への拡大変換がある場合、または引数が通常のラムダである場合、またはデリゲートの戻り値の型へのすべての戻り式からの変換が拡大または縮小された ID である場合、または引数が非同期ラムダであり、デリゲートが Task(Of T) または Task 場合すべての戻り式から T/Object への変換は、少なくとも 1 つの拡大を伴う拡大または ID です。または、引数が反復子ラムダであり、デリゲートが IEnumerator(Of T) または IEnumerable(Of T) または IEnumerator または IEnumerable であり、すべての戻り式から T/Object への変換は、少なくとも 1 つの拡大を伴う拡大または ID です。

    6. ID デリゲートの緩和 -- 引数が AddressOf またはデリゲートと正確に一致するラムダの場合、パラメーターまたは戻り値または生成を拡大または縮小またはドロップしません。次に、セットの一部のメンバーが縮小変換をどの引数にも適用する必要がない場合は、行うすべてのメンバーを削除します。 例えば次が挙げられます。

    Sub f(x As Object)
    End Sub
    
    Sub f(x As Short)
    End Sub
    
    Sub f(x As Short())
    End Sub
    
    f("5") ' picks the Object overload, since String->Short is narrowing
    f(5)   ' picks the Object overload, since Integer->Short is narrowing
    f({5}) ' picks the Object overload, since Integer->Short is narrowing
    f({})  ' a tie-breaker rule subsequent to [3] picks the Short() overload
    
    
  4. 次に、以下のように縮小に基づいて除去を行う。 (Option Strict がオンの場合、縮小を必要とするすべてのメンバーは既に適用不可と判断され ( 引数リストへの適用性セクション)、手順 2 で削除されていることに注意してください)。

    1. セットの一部のインスタンス メンバーが、引数の式型が Objectされる縮小変換のみを必要とする場合は、他のすべてのメンバーを削除します。
    2. セットに、 Objectからのみ縮小する必要がある複数のメンバーが含まれている場合、呼び出しターゲット式は遅延バインディング メソッド アクセスとして再分類されます (メソッド グループを含む型がインターフェイスの場合、または該当するメンバーのいずれかが拡張メンバーであった場合はエラーが発生します)。
    3. 数値リテラルからの絞り込みのみを必要とする候補がある場合は、次の手順で、残りのすべての候補の中で最も具体的な候補を選択します。 勝者が数値リテラルからの縮小のみを必要とする場合は、オーバーロードの解決の結果として選択されます。それ以外の場合はエラーです。

    "注: この規則の正当な理由は、プログラムが緩やかに型指定されている (つまり、ほとんどの変数またはすべての変数が Objectとして宣言されている) 場合、 Object からの多くの変換が縮小されるときにオーバーロードの解決が困難になる可能性があるということです。 オーバーロードの解決が多くの状況で失敗するのではなく (メソッド呼び出しに対する引数の厳密な型指定が必要)、呼び出す適切なオーバーロードされたメソッドの解決は実行時まで延期されます。 これにより、緩やかに型指定された呼び出しは、追加のキャストなしで成功します。 ただし、この残念な副作用は、遅延バインディング呼び出しを実行するには、呼び出しターゲットを Objectにキャストする必要があるということです。 構造体の値の場合は、値を一時ボックス化する必要があることを意味します。 最終的に呼び出されたメソッドが構造体のフィールドを変更しようとすると、メソッドが戻ると、この変更は失われます。 遅延バインディングはランタイム クラスまたは構造体型のメンバーに対して常に解決されるため、インターフェイスはこの特別な規則から除外されます。ランタイム クラスまたは構造体型のメンバーは、実装するインターフェイスのメンバーとは異なる名前を持つ場合があります。

  5. 次に、縮小を必要としないインスタンス メソッドがセット内に残っている場合は、セットからすべての拡張メソッドを削除します。 例えば次が挙げられます。

    Imports System.Runtime.CompilerServices
    
    Class C3
        Sub M1(d As Integer)
        End Sub
    End Class
    
    Module C3Extensions
        <Extension> _
        Sub M1(c3 As C3, c As Long)
        End Sub
    
        <Extension> _
        Sub M1(c3 As C3, c As Short)
        End Sub
    End Module
    
    Module Test
        Sub Main()
            Dim c As New C3()
            Dim sVal As Short = 10
            Dim lVal As Long = 20
    
            ' Calls C3.M1, since C3.M1 is applicable.
            c.M1(sVal)
    
            ' Calls C3Extensions.M1 since C3.M1 requires a narrowing conversion
            c.M1(lVal)
        End Sub
    End Module
    

    "注: インポート (新しい拡張メソッドをスコープに追加する可能性がある) を追加しても既存のインスタンス メソッドの呼び出しが拡張メソッドに再バインドされないことを保証するために、適用可能なインスタンス メソッドがある場合、拡張メソッドは無視されます。 一部の拡張メソッド (つまり、インターフェイスや型パラメーターで定義されているもの) の広い範囲を考えると、これは拡張メソッドにバインドするためのより安全なアプローチです。

  6. 次に、セット MNの 2 つのメンバーがある場合、Mは引数リストに指定されたNよりも具体的です (引数リストに指定されたメンバー/型のセクションの固有性) 場合は、セットからNを削除します。 複数のメンバーがセット内に残っていて、残りのメンバーが引数リストに指定されている場合に等しく固有でない場合、コンパイル時エラーが発生します。

  7. それ以外の場合は、セットの 2 つのメンバー ( MN) に対して、次のタイブレーク ルールを順番に適用します。

    1. Mが ParamArray パラメーターを持たないがN場合、または両方がパラメーターに渡M引数がNよりも少ない場合は、セットからNを削除します。 例えば次が挙げられます。

      Module Test
          Sub F(a As Object, ParamArray b As Object())
              Console.WriteLine("F(Object, Object())")
          End Sub
      
          Sub F(a As Object, b As Object, ParamArray c As Object())
              Console.WriteLine("F(Object, Object, Object())")
          End Sub
      
         Sub G(Optional a As Object = Nothing)
            Console.WriteLine("G(Object)")
         End Sub
      
         Sub G(ParamArray a As Object())
            Console.WriteLine("G(Object())")
         End Sub    Sub Main()
              F(1)
              F(1, 2)
              F(1, 2, 3)
            G()
          End Sub
      End Module
      

      上記の例では、次の出力が生成されます。

      F(Object, Object())
      F(Object, Object, Object())
      F(Object, Object, Object())
      G(Object)
      

      "注: クラスが paramarray パラメーターを使用してメソッドを宣言する場合、展開されたフォームの一部を通常のメソッドとして含めるのも珍しくありません。 そうすることで、paramarray パラメーターを持つメソッドの拡張形式が呼び出されたときに発生する配列インスタンスの割り当てを回避できます。

    2. MNよりも派生型で定義されている場合は、セットからNを削除します。 例えば次が挙げられます。

      Class Base
          Sub F(Of T, U)(x As T, y As U)
          End Sub
      End Class
      
      Class Derived
          Inherits Base
      
          Overloads Sub F(Of T, U)(x As U, y As T)
          End Sub
      End Class
      
      Module Test
          Sub Main()
              Dim d As New Derived()
      
              ' Calls Derived.F
              d.F(10, 10)
          End Sub
      End Module
      

      この規則は、拡張メソッドが定義されている型にも適用されます。 例えば次が挙げられます。

      Imports System.Runtime.CompilerServices
      
      Class Base
      End Class
      
      Class Derived
          Inherits Base
      End Class
      
      Module BaseExt
          <Extension> _
          Sub M(b As Base, x As Integer)
          End Sub
      End Module
      
      Module DerivedExt
          <Extension> _
          Sub M(d As Derived, x As Integer)
          End Sub
      End Module
      
      Module Test
          Sub Main()
              Dim b As New Base()
              Dim d As New Derived()
      
              ' Calls BaseExt.M
              b.M(10)
      
              ' Calls DerivedExt.M 
              d.M(10)
          End Sub
      End Module
      
    3. MNが拡張メソッドであり、Mのターゲット型がクラスまたは構造体であり、Nのターゲット型がインターフェイスである場合は、セットからNを削除します。 例えば次が挙げられます。

      Imports System.Runtime.CompilerServices
      
      Interface I1
      End Interface
      
      Class C1
          Implements I1
      End Class
      
      Module Ext1
          <Extension> _
          Sub M(i As I1, x As Integer)
          End Sub
      End Module
      
      Module Ext2
          <Extension> _
          Sub M(c As C1, y As Integer)
          End Sub
      End Module
      
      Module Test
          Sub Main()
              Dim c As New C1()
      
              ' Calls Ext2.M, because Ext1.M is hidden since it extends
              ' an interface.
              c.M(10)
      
              ' Calls Ext1.M
              CType(c, I1).M(10)
          End Sub
      End Module
      
    4. MNが拡張メソッドであり、型パラメーターの置換後にMNのターゲット型が同一であり、型パラメーターの置換前のMのターゲット型に型パラメーターが含まれていないが、Nのターゲット型の型パラメーターがNのターゲット型よりも少ない場合は、セットからNを削除します。 例えば次が挙げられます。

      Imports System.Runtime.CompilerServices
      
      Module Module1
          Sub Main()
              Dim x As Integer = 1
              x.f(1) ' Calls first "f" extension method
      
              Dim y As New Dictionary(Of Integer, Integer)
              y.g(1) ' Ambiguity error
          End Sub
      
          <Extension()> Sub f(x As Integer, z As Integer)
          End Sub
      
          <Extension()> Sub f(Of T)(x As T, z As T)
          End Sub
      
          <Extension()> Sub g(Of T)(y As Dictionary(Of T, Integer), z As T)
          End Sub
      
          <Extension()> Sub g(Of T)(y As Dictionary(Of T, T), z As T)
          End Sub
      End Module
      
    5. 型引数を置き換える前に、MNよりもジェネリックでない (セクションジェネリック) 場合は、セットからNを排除します。

    6. Mが拡張メソッドではなく、Nされている場合は、セットからNを削除します。

    7. MNが拡張メソッドであり、N (セクション拡張メソッド コレクション) の前にMが見つかった場合は、セットからNを削除します。 例えば次が挙げられます。

      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 Integer)
              End Sub
          End Module
      End Namespace
      
      Namespace N1.N2.N3
          Module Test
              Sub Main()
                  Dim x As New C1()
      
                  ' Calls N2C1Extensions.M1
                  x.M1(10)
              End Sub
          End Module
      End Namespace
      

      拡張メソッドが同じ手順で見つかった場合、それらの拡張メソッドはあいまいです。 呼び出しは、拡張メソッドを含む標準モジュールの名前を使用して、通常のメンバーであるかのように拡張メソッドを呼び出すことで、常にあいまいさを解消できます。 例えば次が挙げられます。

      Imports System.Runtime.CompilerServices
      
      Class C1
      End Class
      
      Module C1ExtA
          <Extension> _
          Sub M(c As C1)
          End Sub
      End Module
      
      Module C1ExtB
          <Extension> _
          Sub M(c As C1)
          End Sub
      End Module
      
      Module Main
          Sub Test()
              Dim c As New C1()
      
              C1.M()               ' Ambiguous between C1ExtA.M and BExtB.M
              C1ExtA.M(c)          ' Calls C1ExtA.M
              C1ExtB.M(c)          ' Calls C1ExtB.M
          End Sub
      End Module
      
    8. MN両方で型引数を生成するために必要な型推論が必要であり、Mがその型引数 (つまり、各型引数が 1 つの型に推論される) の主型を決定する必要がない場合、Nは、セットからNを排除します。

      "注: この規則により、以前のバージョンで成功したオーバーロード解決 (型引数に対して複数の型を推論するとエラーが発生する場合) は、引き続き同じ結果が生成されます。

    9. AddressOf式からデリゲート作成式のターゲットを解決するためにオーバーロード解決が行われている場合、デリゲートとMの両方が関数であり、Nがサブルーチンである場合は、セットからNを削除します。 同様に、デリゲートと M の両方がサブルーチンであり、 N が関数である場合は、セットから N を排除します。

    10. M明示的な引数の代わりに省略可能なパラメーターの既定値を使用しなかったが、N場合は、セットからNを削除します。

    11. 型引数を置き換える前に、MNよりもジェネリックの深さ (セクションジェネリック) を持っている場合は、セットからNを削除します。

  8. それ以外の場合、呼び出しはあいまいであり、コンパイル時エラーが発生します。

引数リストを指定したメンバー/型の特定性

メンバー Mは、引数リストのA、シグネチャが同じ場合、またはMの各パラメーター型がNの対応するパラメーター型と同じである場合、N同じように固有と見なされます。

"注: 拡張メソッドが原因で、2 つのメンバーが同じシグネチャを持つメソッド グループに入る可能性があります。 また、型パラメーターまたは paramarray の拡張により、2 つのメンバーも同じように固有ですが、同じシグネチャを持つわけではありません。

シグネチャが異なり、Mの少なくとも 1 つのパラメーター型がNのパラメーター型よりも具体的であり、Nのパラメーター型がMのパラメーター型よりも具体的でない場合、メンバー MNよりも具体的であると見なされます。 引数Ajに一致するパラメーターMjNjのペアが指定された場合、次のいずれかの条件に該当する場合、Mjの型はNjの型よりも具体的であると見なされます。

  • Mjの型からNj型への拡大変換が存在します。 (注。 この場合、パラメーター型は実際の引数に関係なく比較されるため、定数式から値が収まる数値型への拡大変換は考慮されません)。

  • Aj はリテラル 0Mj は数値型、 Nj は列挙型です。 (注。 リテラル 0 は列挙された型に拡大されるため、この規則が必要です。列挙型は基になる型に拡大されるため、これは、 0 でのオーバーロードの解決が既定で、数値型よりも列挙型を優先することを意味します。この動作は直感に反するという多くのフィードバックを受け取りました。)

  • Mj Njはどちらも数値型であり、Mjはリスト ByteSByteShortUShortIntegerUIntegerLongULongDecimalSingleDoubleNjよりも前に取得されます。 (注。 特定のサイズの符号付き数値型と符号なし数値型の間には縮小変換しかないため、数値型に関する規則が役立ちます。上記の規則では、より "自然な" 数値型を優先して、2 つの型間の結びつきが解除されます。これは、特定のサイズの符号付き数値型と符号なし数値型の両方に広がる型 (たとえば、両方に収まる数値リテラル) に対してオーバーロード解決を行う場合に特に重要です)。

  • Mj Njはデリゲート関数型であり、Mjの戻り値の型はNjの戻り値の型よりも具体的です。Ajがラムダ メソッドとして分類され、MjまたはNjSystem.Linq.Expressions.Expression(Of T)場合、型の型引数 (デリゲート型であると仮定) が比較される型に置き換わります。

  • MjAjの種類と同じであり、 Nj は同じではありません。 (注。 興味深いことに、前の規則は C# とは若干異なります。C# では、戻り値の型を比較する前にデリゲート関数の型に同じパラメーター リストが必要ですが、Visual Basic では同じではありません)。

ジェネリック性

メンバー Mは、次のようにメンバーNよりもジェネリックでないと判断されます。

  1. 一致するパラメーター MjNjのペアごとに、 Mj がメソッドの型パラメーターに関して Nj 以下または等しいジェネリックであり、メソッドの型パラメーターに関して少なくとも 1 つの Mj がジェネリックでない場合。
  2. それ以外の場合、一致するパラメーター MjNjのペアごとに、 Mj が型の型パラメーターに関して Nj 以下または等しいジェネリックであり、型の型パラメーターに関して少なくとも 1 つの Mj がジェネリックでない場合、 MNよりもジェネリックではありません。

パラメーターMは、型MtNtの両方が型パラメーターを参照している場合、または両方が型パラメーターを参照しない場合に、パラメーター Nに対して同様にジェネリックであると見なされます。 Mは、Mtが型パラメーターを参照せず、Ntが参照する場合、Nよりもジェネリックでないと見なされます。

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

Class C1(Of T)
    Sub S1(Of U)(x As U, y As T)
    End Sub

    Sub S1(Of U)(x As U, y As U)
    End Sub

    Sub S2(x As Integer, y As T)
    End Sub

    Sub S2(x As T, y As T)
    End Sub
End Class

Module Test
    Sub Main()
        Dim x As C1(Of Integer) = New C1(Of Integer)

        x.S1(10, 10)    ' Calls S1(U, T)
        x.S2(10, 10)    ' Calls S2(Integer, T)
    End Sub
End Module

カレー処理中に修正された拡張メソッド型パラメーターは、メソッドの型パラメーターではなく、型パラメーターと見なされます。 例えば次が挙げられます。

Imports System.Runtime.CompilerServices

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

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

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

        i.M1(10, 10)
    End Sub
End Module

ジェネリックの深さ

一致するパラメーターMjNjのペアごとに、MjNj以上のジェネリック性を持ち、少なくとも 1 つのMjの方がジェネリック性の深さが大きい場合、メンバー Mはメンバー Nよりもジェネリックの深さが大きいと判断されます。 ジェネリックの深さは次のように定義されます。

  • 型パラメーター以外の場合は、型パラメーターよりもジェネリック性の深さが大きくなります。

  • 少なくとも 1 つの型引数のジェネリックの深さが大きく、型引数が他の型引数の対応する型引数よりも深さが少ない場合、構築された型は、他の構築型 (型引数の数が同じ) よりもジェネリックの深さが大きくなります。

  • 配列型は、1 番目の要素型が 2 番目の要素型よりもジェネリック性の深さが大きい場合、別の配列型 (次元数が同じ) よりもジェネリックの深さが大きくなります。

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

Module Test

    Sub f(Of T)(x As Task(Of T))
    End Sub

    Sub f(Of T)(x As T)
    End Sub

    Sub Main()
        Dim x As Task(Of Integer) = Nothing
        f(x)            ' Calls the first overload
    End Sub
End Module

引数リストへの適用性

メソッドは、引数リストを使用してメソッドを呼び出すことができる場合、型引数、位置引数、および名前付き引数のセットに 適用 できます。 引数リストは、次のようにパラメーター リストと照合されます。

  1. まず、各位置引数をメソッド パラメーターの一覧に一致させます。 パラメーターよりも多くの位置引数があり、最後のパラメーターが paramarray でない場合、メソッドは適用されません。 それ以外の場合、paramarray パラメーターは、位置引数の数と一致するように paramarray 要素型のパラメーターで展開されます。 paramarray に入る位置引数を省略した場合、メソッドは適用されません。
  2. 次に、各名前付き引数を、指定された名前のパラメーターと照合します。 名前付き引数の 1 つが一致しない場合、paramarray パラメーターと一致する場合、または別の位置指定引数または名前付き引数と既に一致している引数と一致する場合、メソッドは適用されません。
  3. 次に、型引数が指定されている場合は、型パラメーター リストと照合されます。 2 つのリストに同じ数の要素がない場合、型引数リストが空でない限り、メソッドは適用されません。 型引数リストが空の場合、型引数リストを試して推論するために型推論が使用されます。 型推論が失敗した場合、メソッドは適用されません。 それ以外の場合、型引数はシグネチャの型パラメーターの代わりに入力されます。一致していないパラメーターが省略可能でない場合、メソッドは適用されません。
  4. 引数式が一致するパラメーターの型に暗黙的に変換できない場合、メソッドは適用されません。
  5. パラメーターが ByRef で、パラメーターの型から引数の型への暗黙的な変換がない場合、メソッドは適用されません。
  6. 型引数がメソッドの制約 (手順 3 の推定型引数を含む) に違反している場合、メソッドは適用されません。 例えば次が挙げられます。
Module Module1
    Sub Main()
        f(Of Integer)(New Exception)
        ' picks the first overload (narrowing),
        ' since the second overload (widening) violates constraints 
    End Sub

    Sub f(Of T)(x As IComparable)
    End Sub

    Sub f(Of T As Class)(x As Object)
    End Sub
End Module

1 つの引数式が paramarray パラメーターと一致し、引数式の型が paramarray パラメーターの型と paramarray 要素型の両方に変換できる場合、メソッドは展開されたフォームと展開されていないフォームの両方で適用でき、2 つの例外があります。 引数式の型から paramarray 型への変換が縮小されている場合、メソッドは展開された形式でのみ適用されます。 引数式がリテラル Nothingの場合、メソッドは、その展開されていない形式でのみ適用できます。 例えば次が挙げられます。

Module Test
    Sub F(ParamArray a As Object())
        Dim o As Object

        For Each o In a
            Console.Write(o.GetType().FullName)
            Console.Write(" ")
        Next o
        Console.WriteLine()
    End Sub

    Sub Main()
        Dim a As Object() = { 1, "Hello", 123.456 }
        Dim o As Object = a

        F(a)
        F(CType(a, Object))
        F(o)
        F(CType(o, Object()))
    End Sub
End Module

上記の例では、次の出力が生成されます。

System.Int32 System.String System.Double
System.Object[]
System.Object[]
System.Int32 System.String System.Double

Fの最初と最後の呼び出しでは、通常の形式のFが適用されます。これは、引数の型からパラメーター型への拡大変換が存在し (両方ともObject()型)、引数が標準値パラメーターとして渡されるためです。 2 番目と 3 番目の呼び出しでは、引数の型からパラメーター型への拡大変換が存在しないため、通常の形式の F は適用できません ( Object から Object() への変換は縮小されます)。 ただし、拡張形式の F が適用され、呼び出しによって 1 要素 Object() が作成されます。 配列の 1 つの要素は、指定された引数値 (それ自体が Object()への参照) で初期化されます。

省略可能なパラメーターの引数の受け渡しと引数の選択

パラメーターが値パラメーターの場合は、一致する引数式を値として分類する必要があります。 値はパラメーターの型に変換され、実行時にパラメーターとして渡されます。 パラメーターが参照パラメーターで、一致する引数式がパラメーターと同じ型の変数として分類されている場合、実行時に変数への参照がパラメーターとして渡されます。

それ以外の場合、一致する引数式が変数、値、またはプロパティ アクセスとして分類される場合、パラメーターの型の一時変数が割り当てられます。 実行時にメソッドを呼び出す前に、引数式が値として再分類され、パラメーターの型に変換され、一時変数に割り当てられます。 その後、一時変数への参照がパラメーターとして渡されます。 メソッド呼び出しが評価された後、引数式が変数またはプロパティ アクセスとして分類されている場合、一時変数は変数式またはプロパティ アクセス式に割り当てられます。 プロパティ アクセス式に Set アクセサーがない場合、割り当ては実行されません。

引数が指定されていない省略可能なパラメーターの場合、コンパイラは以下の説明に従って引数を選択します。 いずれの場合も、ジェネリック型の置換後にパラメーター型に対してテストします。

  • 省略可能なパラメーターに属性 System.Runtime.CompilerServices.CallerLineNumberがあり、呼び出しがソース コード内の場所からのものであり、その場所の行番号を表す数値リテラルがパラメーター型への組み込み変換を持つ場合、数値リテラルが使用されます。 呼び出しが複数行にまたがる場合、使用する行の選択は実装に依存します。

  • 省略可能なパラメーターに属性 System.Runtime.CompilerServices.CallerFilePathがあり、呼び出しがソース コード内の場所からのものであり、その場所のファイル パスを表す文字列リテラルがパラメーター型への組み込み変換を持つ場合、文字列リテラルが使用されます。 ファイル パスの形式は実装に依存します。

  • 省略可能なパラメーターに属性 System.Runtime.CompilerServices.CallerMemberNameがあり、呼び出しが型メンバーの本体内、またはその型メンバーの任意の部分に適用された属性内にあり、そのメンバー名を表す文字列リテラルがパラメーター型への組み込み変換を持つ場合、文字列リテラルが使用されます。 プロパティ アクセサーまたはカスタム イベント ハンドラーの一部である呼び出しの場合、使用されるメンバー名はプロパティまたはイベント自体のメンバー名になります。 演算子またはコンストラクターの一部である呼び出しの場合は、実装固有の名前が使用されます。

上記のいずれも適用されない場合は、省略可能なパラメーターの既定値が使用されます (既定値が指定されていない場合は Nothing )。 また、上記の複数が適用される場合、使用する選択肢は実装に依存します。

CallerLineNumber属性とCallerFilePath属性は、ログ記録に役立ちます。 CallerMemberNameは、INotifyPropertyChangedの実装に役立ちます。 例を次に示します。

Sub Log(msg As String,
        <CallerFilePath> Optional file As String = Nothing,
        <CallerLineNumber> Optional line As Integer? = Nothing)
    Console.WriteLine("{0}:{1} - {2}", file, line, msg)
End Sub

WriteOnly Property p As Integer
    Set(value As Integer)
        Notify(_p, value)
    End Set
End Property

Private _p As Integer

Sub Notify(Of T As IEquatable(Of T))(ByRef v1 As T, v2 As T,
        <CallerMemberName> Optional prop As String = Nothing)
    If v1 IsNot Nothing AndAlso v1.Equals(v2) Then Return
    If v1 Is Nothing AndAlso v2 Is Nothing Then Return
    v1 = v2
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
End Sub

上記の省略可能なパラメーターに加えて、Microsoft Visual Basic では、メタデータ (つまり DLL 参照から) からインポートされた場合、追加の省略可能なパラメーターも認識されます。

  • メタデータからインポートすると、Visual Basic はパラメーター <Optional> をパラメーターが省略可能であることを示すものとして扱います。この方法では、 Optional キーワードを使用して表現できない場合でも、省略可能なパラメーターを持ち、既定値を持たない宣言をインポートできます。

  • 省略可能なパラメーターに属性 Microsoft.VisualBasic.CompilerServices.OptionCompareAttributeがあり、数値リテラル 1 または 0 にパラメーター型への変換がある場合、コンパイラは、 Option Compare Text が有効な場合はリテラル 1、有効な場合はリテラル 0 を引数として使用 Optional Compare Binary

  • 省略可能なパラメーターに属性 System.Runtime.CompilerServices.IDispatchConstantAttributeがあり、型 Objectがあり、既定値を指定しない場合、コンパイラは引数 New System.Runtime.InteropServices.DispatchWrapper(Nothing)を使用します。

  • 省略可能なパラメーターに属性 System.Runtime.CompilerServices.IUnknownConstantAttributeがあり、型 Objectがあり、既定値を指定しない場合、コンパイラは引数 New System.Runtime.InteropServices.UnknownWrapper(Nothing)を使用します。

  • 省略可能なパラメーターに型 Objectがあり、既定値が指定されていない場合、コンパイラは引数 System.Reflection.Missing.Valueを使用します。

条件付きメソッド

呼び出し式が参照するターゲット メソッドが、インターフェイスのメンバーではないサブルーチンであり、メソッドに 1 つ以上の System.Diagnostics.ConditionalAttribute 属性がある場合、式の評価は、ソース ファイルのその時点で定義されている条件付きコンパイル定数に依存します。 属性の各インスタンスは、条件付きコンパイル定数に名前を付ける文字列を指定します。 各条件付きコンパイル定数は、条件付きコンパイル ステートメントの一部であるかのように評価されます。 定数が Trueに評価された場合、式は実行時に通常どおりに評価されます。 定数が Falseに評価された場合、式はまったく評価されません。

属性を検索すると、オーバーライド可能なメソッドの最も派生した宣言がチェックされます。

"注: この属性は、関数またはインターフェイス メソッドでは無効であり、いずれかの種類のメソッドで指定されている場合は無視されます。 したがって、条件付きメソッドは呼び出しステートメントにのみ表示されます。

型引数の推論

型引数を指定せずに型パラメーターを持つメソッドが呼び出されると、 型引数の推論 を使用して、呼び出しの型引数を試して推論します。 これにより、型引数を簡単に推論できる場合に、型パラメーターを持つメソッドを呼び出すために、より自然な構文を使用できます。 たとえば、次のメソッド宣言があるとします。

Module Util
    Function Choose(Of T)(b As Boolean, first As T, second As T) As T
        If b Then
            Return first
        Else
            Return second
        End If
    End Function
End Class

型引数を明示的に指定せずに、 Choose メソッドを呼び出すことができます。

' calls Choose(Of Integer)
Dim i As Integer = Util.Choose(True, 5, 213)
' calls Choose(Of String)
Dim s As String = Util.Choose(False, "a", "b") 

型引数の推論により、型引数 IntegerString は、引数からメソッドに対して決定されます。

型引数の推論は、式の再分類が引数リスト内のラムダ メソッドまたはメソッド ポインターに対して実行される に発生します。これらの 2 種類の式の再分類には、パラメーターの型を知る必要がある場合があるためです。 一連の引数 A1,...,An、一致するパラメーターのセット P1,...,Pn 、および一連のメソッド型パラメーター T1,...,Tn、引数とメソッド型パラメーターの間の依存関係は、最初に次のように収集されます。

  • AnNothing リテラルの場合、依存関係は生成されません。

  • Anがラムダ メソッドであり、Pnの型が構築されたデリゲート型またはSystem.Linq.Expressions.Expression(Of T)である場合、Tは構築されたデリゲート型です。

  • ラムダ メソッド パラメーターの型が対応するパラメーター Pnの型から推論され、パラメーターの型が Tnメソッドの型パラメーターに依存している場合、 AnTnに依存します。

  • ラムダ メソッド パラメーターの型が指定され、対応するパラメーターの型 Pn がメソッド型パラメーター Tnに依存する場合、 TnAnに依存します。

  • Pnの戻り値の型がメソッド型パラメーターTnに依存している場合、TnAnに依存します。

  • Anがメソッド ポインターであり、Pnの型が構築されたデリゲート型である場合、

  • Pnの戻り値の型がメソッド型パラメーターTnに依存している場合、TnAnに依存します。

  • Pnが構築された型であり、Pnの型がTnメソッドの型パラメーターに依存している場合、TnAnに依存します。

  • それ以外の場合、依存関係は生成されません。

依存関係を収集すると、依存関係のない引数はすべて削除されます。 メソッド型パラメーターに送信依存関係がない場合 (つまり、メソッド型パラメーターが引数に依存しない場合)、型の推論は失敗します。 それ以外の場合、残りの引数とメソッド型パラメーターは、厳密に接続されたコンポーネントにグループ化されます。 厳密に接続されたコンポーネントは、引数とメソッド型パラメーターのセットです。このパラメーターでは、コンポーネント内の要素は、他の要素への依存関係を介して到達可能です。

その後、強く接続されたコンポーネントはトポロジ的に並べ替えられてトポロジ順に処理されます。

  • 厳密に型指定されたコンポーネントに含まれる要素が 1 つだけの場合、

    • 要素が既に完了とマークされている場合は、スキップします。

    • 要素が引数の場合は、引数から依存するメソッド型パラメーターに型ヒントを追加し、要素を完全としてマークします。 引数が推論された型を必要とするパラメーターを持つラムダ メソッドの場合は、それらのパラメーターの型の Object を推論します。

    • 要素がメソッド型パラメーターの場合は、メソッド型パラメーターを引数型ヒントの中で優先型として推論し、要素を完了としてマークします。 型ヒントに配列要素の制限がある場合は、指定された型の配列間で有効な変換のみが考慮されます (つまり、共変と組み込みの配列変換)。 型ヒントにジェネリック引数の制限がある場合は、ID 変換のみが考慮されます。 主要な型を選択できない場合、推論は失敗します。 ラムダ メソッドの引数型がこのメソッド型パラメーターに依存している場合、その型はラムダ メソッドに伝達されます。

  • 厳密に型指定されたコンポーネントに複数の要素が含まれている場合、コンポーネントにはサイクルが含まれます。

    • コンポーネント内の要素であるメソッド型パラメーターごとに、メソッド型パラメーターが完全とマークされていない引数に依存している場合は、その依存関係を推論プロセスの最後にチェックされるアサーションに変換します。

    • 厳密に型指定されたコンポーネントが決定された時点で、推論プロセスを再開します。

すべてのメソッド型パラメーターに対して型の推論が成功した場合、アサーションに変更されたすべての依存関係がチェックされます。 引数の型が、メソッド型パラメーターの推論された型に暗黙的に変換できる場合、アサーションは成功します。 アサーションが失敗した場合、型引数の推論は失敗します。

引数Aの引数型Taとパラメーター Pのパラメーター型Tpを指定すると、型ヒントは次のように生成されます。

  • Tpにメソッド型パラメーターが含まれていない場合、ヒントは生成されません。

  • TpTaが同じランクの配列型である場合は、TaTpTaおよびTpの要素型に置き換え、配列要素の制限でこのプロセスを再開します。

  • Tpがメソッド型パラメーターの場合、現在の制限がある場合は、Taが型ヒントとして追加されます。

  • Aがラムダ メソッドであり、Tpが構築されたデリゲート型またはSystem.Linq.Expressions.Expression(Of T)である場合、Tは構築されたデリゲート型であり、各ラムダ メソッド パラメーター型TLおよび対応するデリゲート パラメーター型TDに対して、TaTLに置き換え、TpTDに置き換え、制限なくプロセスを再開します。 次に、 Ta をラムダ メソッドの戻り値の型に置き換え、次のようにします。

    • Aが通常のラムダ メソッドの場合は、Tpをデリゲート型の戻り値の型に置き換えます。
    • Aが非同期ラムダ メソッドであり、デリゲート型の戻り値の型が何らかのTのフォーム Task(Of T)を持つ場合は、TpをそのTに置き換えます。
    • Aが反復子ラムダ メソッドであり、デリゲート型の戻り値の型が何らかのTのフォーム IEnumerator(Of T)またはIEnumerable(Of T)を持つ場合は、TpをそのTに置き換えます。
    • 次に、制限なしでプロセスを再起動します。
  • Aがメソッド ポインターであり、Tpが構築されたデリゲート型である場合は、Tpのパラメーター型を使用して、Tpに最も適用できるメソッドを判断します。 最も適切なメソッドがある場合は、 Ta をメソッドの戻り値の型に置き換え、 Tp デリゲート型の戻り値の型に置き換え、制限なしでプロセスを再開します。

  • それ以外の場合、 Tp は構築された型である必要があります。 TGTpのジェネリック型、

    • TaTGTGから継承、または型TGを 1 回だけ実装した場合は、一致する型引数 TaxTaTpTpxごとに、TaTaxに置き換え、TpxTpし、一般的な引数制限でプロセスを再開します。

    • それ以外の場合、ジェネリック メソッドの型推論は失敗します。

型推論が成功しても、メソッドが適用されるとは限りません。