Bagikan melalui


Resolusi Metode Kelebihan Beban

Dalam praktiknya, aturan untuk menentukan resolusi kelebihan beban dimaksudkan untuk menemukan kelebihan beban yang "paling dekat" dengan argumen aktual yang disediakan. Jika ada metode yang jenis parameternya cocok dengan jenis argumen, maka metode tersebut jelas yang paling dekat. Melarangnya, satu metode lebih dekat dari metode lain jika semua jenis parameternya lebih sempit daripada (atau sama dengan) jenis parameter metode lainnya. Jika tidak ada parameter metode yang lebih sempit dari yang lain, maka tidak ada cara untuk menentukan metode mana yang lebih dekat dengan argumen.

Nota. Resolusi kelebihan beban tidak memperhitungkan jenis pengembalian metode yang diharapkan.

Perhatikan juga bahwa karena sintaks parameter bernama, pengurutan parameter aktual dan formal mungkin tidak sama.

Mengingat grup metode, metode yang paling berlaku dalam grup untuk daftar argumen ditentukan menggunakan langkah-langkah berikut. Jika, setelah menerapkan langkah tertentu, tidak ada anggota yang tetap berada dalam set, maka kesalahan waktu kompilasi terjadi. Jika hanya satu anggota yang tetap berada di set, maka anggota tersebut adalah anggota yang paling berlaku. Langkah-langkahnya adalah:

  1. Pertama, jika tidak ada argumen jenis yang disediakan, terapkan inferensi jenis ke metode apa pun yang memiliki parameter jenis. Jika inferensi jenis berhasil untuk metode, maka argumen jenis yang disimpulkan digunakan untuk metode tertentu. Jika inferensi jenis gagal untuk metode, maka metode tersebut dihilangkan dari set.

  2. Selanjutnya, hilangkan semua anggota dari set yang tidak dapat diakses atau tidak berlaku (Bagian Penerapan Ke Daftar Argumen) ke daftar argumen

  3. Selanjutnya, jika satu atau beberapa argumen adalah AddressOf atau ekspresi lambda, maka hitung tingkat relaksasi delegasi untuk setiap argumen seperti di bawah ini. Jika tingkat relaksasi delegasi terburuk (terendah) masuk N lebih buruk daripada tingkat relaksasi delegasi terendah di M, maka hilangkan N dari set. Tingkat relaksasi delegasi adalah sebagai berikut:

    1. Kesalahan mendelegasikan tingkat relaksasi -- jika AddressOf atau lambda tidak dapat dikonversi ke jenis delegasi.

    2. Mempersempit relaksasi jenis pengembalian atau parameter -- jika argumen adalah AddressOf atau lambda dengan jenis yang dinyatakan dan konversi dari jenis pengembaliannya ke jenis pengembalian delegasi menyempit; atau jika argumen adalah lambda biasa dan konversi dari salah satu ekspresi pengembaliannya ke jenis pengembalian delegasi menyempit, atau jika argumen adalah lambda asinkron dan jenis pengembalian delegasi adalah Task(Of T) dan konversi dari salah satu ekspresi T pengembaliannya menjadi menyempit; atau jika argumen adalah lambda iterator dan jenis IEnumerator(Of T) pengembalian delegasi atau IEnumerable(Of T) dan konversi dari salah satu operan hasilnya menjadi T menyempit.

    3. Pelesiran mendelegasikan relaksasi untuk mendelegasikan tanpa tanda tangan -- jika jenis delegasi adalah System.Delegate atau System.MultiCastDelegate atau System.Object.

    4. Drop return atau argumen mendelegasikan relaksasi -- jika argumen adalah AddressOf atau lambda dengan jenis pengembalian yang dinyatakan dan jenis delegasi tidak memiliki jenis pengembalian; atau jika argumen adalah lambda dengan satu atau beberapa ekspresi pengembalian dan jenis delegasi tidak memiliki jenis pengembalian; atau jika argumen adalah AddressOf atau lambda tanpa parameter dan jenis delegasi memiliki parameter.

    5. Memperlebar relaksasi delegasi jenis pengembalian -- jika argumen adalah AddressOf atau lambda dengan jenis pengembalian yang dinyatakan, dan ada konversi yang melebar dari jenis pengembaliannya ke delegasi; atau jika argumen adalah lambda reguler di mana konversi dari semua ekspresi pengembalian ke jenis pengembalian delegasi melebar atau identitas dengan setidaknya satu pelesiran; atau jika argumen adalah lambda asinkron dan delegasi adalah Task(Of T) atau Task dan konversi dari semua ekspresi pengembalian ke T/Object masing-masing melebar atau identitas dengan setidaknya satu pelesiran; atau jika argumen adalah lambda iterator dan delegasi adalah IEnumerator(Of T) atau atau IEnumerable(Of T) atau IEnumeratorIEnumerable dan konversi dari semua ekspresi pengembalian menjadi T/Object melebar atau identitas dengan setidaknya satu pellebaran.

    6. Relaksasi delegasi identitas -- jika argumen adalah AddressOf atau lambda yang cocok dengan delegasi dengan tepat, tanpa pelebaran atau penyempitan atau penurunan parameter atau pengembalian atau hasil. Selanjutnya, jika beberapa anggota set tidak mengharuskan konversi yang dipersempit berlaku untuk salah satu argumen, maka hilangkan semua anggota yang melakukannya. Contohnya:

    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. Selanjutnya, eliminasi dilakukan berdasarkan penyempitan sebagai berikut. (Perhatikan bahwa, jika Opsi Ketat Aktif, maka semua anggota yang memerlukan penyempitan telah dinilai tidak dapat diterapkan (Bagian Berlaku Untuk Daftar Argumen) dan dihapus oleh Langkah 2.)

    1. Jika beberapa anggota instans set hanya memerlukan konversi yang mempersempit di mana jenis ekspresi argumen adalah Object, maka hilangkan semua anggota lain.
    2. Jika set berisi lebih dari satu anggota yang hanya memerlukan penyempitan dari Object, maka ekspresi target pemanggilan diklasifikasikan ulang sebagai akses metode terikat terlambat (dan kesalahan diberikan jika jenis yang berisi grup metode adalah antarmuka, atau jika salah satu anggota yang berlaku adalah anggota ekstensi).
    3. Jika ada kandidat yang hanya memerlukan penyempitan dari literal numerik, maka pilih yang paling spesifik di antara semua kandidat yang tersisa dengan langkah-langkah di bawah ini. Jika pemenang hanya memerlukan penyempitan dari literal numerik, maka dipilih sebagai hasil dari resolusi kelebihan beban; jika tidak, itu adalah kesalahan.

    Nota. Pembenaran untuk aturan ini adalah bahwa jika program diketik secara longgar (yaitu, sebagian besar atau semua variabel dinyatakan sebagai Object), resolusi kelebihan beban bisa sulit ketika banyak konversi dari Object penyempitan. Daripada resolusi kelebihan beban gagal dalam banyak situasi (membutuhkan pengetikan argumen yang kuat ke panggilan metode), resolusi metode kelebihan beban yang sesuai untuk panggilan ditangguhkan sampai run time. Ini memungkinkan panggilan yang diketik secara longgar berhasil tanpa cast tambahan. Efek samping yang tidak menguntungkan dari ini, bagaimanapun, adalah bahwa melakukan panggilan terlambat terikat memerlukan transmisi target panggilan ke Object. Dalam kasus nilai struktur, ini berarti bahwa nilai harus dikotak ke sementara. Jika metode akhirnya disebut mencoba mengubah bidang struktur, perubahan ini akan hilang setelah metode kembali. Antarmuka dikecualikan dari aturan khusus ini karena pengikatan terlambat selalu diselesaikan terhadap anggota kelas runtime atau jenis struktur, yang mungkin memiliki nama yang berbeda dari anggota antarmuka yang mereka terapkan.

  5. Selanjutnya, jika ada metode instans yang tetap dalam set yang tidak memerlukan penyempitan, maka hilangkan semua metode ekstensi dari set. Contohnya:

    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
    

    Nota. Metode ekstensi diabaikan jika ada metode instans yang berlaku untuk menjamin bahwa menambahkan impor (yang mungkin membawa metode ekstensi baru ke dalam cakupan) tidak akan menyebabkan panggilan pada metode instans yang ada untuk diikat ulang ke metode ekstensi. Mengingat cakupan luas dari beberapa metode ekstensi (yaitu yang ditentukan pada antarmuka dan/atau parameter jenis), ini adalah pendekatan yang lebih aman untuk mengikat metode ekstensi.

  6. Selanjutnya, jika, mengingat dua anggota set M dan N, M lebih spesifik ( Kekhususan Bagian anggota/jenis diberikan daftar argumen) daripada N yang diberikan daftar argumen, hilangkan N dari set. Jika lebih dari satu anggota tetap dalam set dan anggota yang tersisa tidak sama spesifiknya mengingat daftar argumen, hasil kesalahan waktu kompilasi.

  7. Jika tidak, mengingat dua anggota set, M dan N, terapkan aturan pemecahan ikatan berikut, secara berurutan:

    1. Jika M tidak memiliki parameter ParamArray tetapi N tidak, atau jika keduanya melakukannya tetapi M meneruskan lebih sedikit argumen ke parameter ParamArray daripada N yang dilakukan, maka hilangkan N dari set. Contohnya:

      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
      

      Contoh di atas menghasilkan output berikut:

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

      Nota. Ketika kelas mendeklarasikan metode dengan parameter paramarray, tidak jarang juga menyertakan beberapa bentuk yang diperluas sebagai metode reguler. Dengan demikian, dimungkinkan untuk menghindari alokasi instans array yang terjadi ketika bentuk metode yang diperluas dengan parameter paramarray dipanggil.

    2. Jika M didefinisikan dalam jenis yang lebih turunan daripada N, hilangkan N dari set. Contohnya:

      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
      

      Aturan ini juga berlaku untuk jenis yang didefinisikan oleh metode ekstensi. Contohnya:

      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. Jika M dan N merupakan metode ekstensi dan jenis M target adalah kelas atau struktur dan jenis N target adalah antarmuka, hilangkan N dari set. Contohnya:

      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. Jika M dan N merupakan metode ekstensi, dan jenis M target dan N identik setelah penggantian parameter jenis, dan jenis target dari M sebelum jenis penggantian parameter tidak berisi parameter jenis tetapi jenis N target tidak, maka memiliki lebih sedikit parameter jenis daripada jenis Ntarget , hilangkan N dari set. Contohnya:

      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. Sebelum argumen jenis telah diganti, jika Mkurang umum ( Generikitas Bagian) daripada N, hilangkan N dari set.

    6. Jika M bukan metode ekstensi dan N adalah, hilangkan N dari set.

    7. Jika M dan N merupakan metode ekstensi dan M ditemukan sebelumnya N ( Kumpulan Metode Ekstensi Bagian), hilangkan N dari set. Contohnya:

      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
      

      Jika metode ekstensi ditemukan dalam langkah yang sama, maka metode ekstensi tersebut ambigu. Panggilan mungkin selalu terdisambiguasi menggunakan nama modul standar yang berisi metode ekstensi dan memanggil metode ekstensi seolah-olah itu adalah anggota biasa. Contohnya:

      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. Jika M dan N kedua inferensi jenis yang diperlukan untuk menghasilkan argumen jenis, dan M tidak memerlukan penentuan jenis dominan untuk salah satu argumen jenisnya (yaitu setiap argumen jenis yang disimpulkan ke satu jenis), tetapi N tidak, hilangkan N dari set.

      Nota. Aturan ini memastikan bahwa resolusi kelebihan beban yang berhasil dalam versi sebelumnya (di mana menyimpulkan beberapa jenis untuk argumen jenis akan menyebabkan kesalahan), terus menghasilkan hasil yang sama.

    9. Jika resolusi kelebihan beban sedang dilakukan untuk menyelesaikan target ekspresi pembuatan delegasi dari AddressOf ekspresi, dan delegasi dan M merupakan fungsi sementara N merupakan subroutine, hilangkan N dari set. Demikian juga, jika delegasi dan M merupakan subroutine, sementara N itu adalah fungsi, hilangkan N dari set.

    10. Jika M tidak menggunakan default parameter opsional sebagai pengganti argumen eksplisit, tetapi N melakukannya, maka hilangkan N dari set.

    11. Sebelum argumen jenis diganti, jika M memiliki kedalaman generikitas yang lebih besar ( Generikitas Bagian) daripada N, maka hilangkan N dari set.

  8. Jika tidak, panggilan bersifat ambigu dan terjadi kesalahan waktu kompilasi.

Kekhususan anggota/jenis yang diberi daftar argumen

Anggota M dianggap sama spesifiknya dengan N, diberikan daftar Aargumen , jika tanda tangan mereka sama atau jika setiap jenis M parameter sama dengan jenis parameter yang sesuai di N.

Nota. Dua anggota dapat berakhir dalam grup metode dengan tanda tangan yang sama karena metode ekstensi. Dua anggota juga dapat sama-sama spesifik tetapi tidak memiliki tanda tangan yang sama karena parameter jenis atau ekspansi paramarray.

Anggota M dianggap lebih spesifik daripada N jika tanda tangan mereka berbeda dan setidaknya satu jenis parameter di M lebih spesifik daripada jenis parameter di N, dan tidak ada jenis parameter yang N lebih spesifik daripada jenis parameter di M. Mengingat sepasang parameter Mj dan Nj yang cocok dengan argumen Aj, jenis Mj dianggap lebih spesifik daripada jenis Nj jika salah satu kondisi berikut ini benar:

  • Ada konversi yang melebar dari jenis ke jenis MjNj. (Catatan. Karena jenis parameter sedang dibandingkan tanpa memperhatikan argumen aktual dalam kasus ini, konversi yang melebar dari ekspresi konstanta ke jenis numerik yang cocok dengan nilai tidak dipertimbangkan dalam kasus ini.)

  • Aj adalah literal 0, Mj adalah jenis numerik dan Nj merupakan jenis enumerasi. (Catatan. Aturan ini diperlukan karena harfiah 0 melebar ke jenis enumerasi apa pun. Karena jenis enumerasi melebar ke jenis yang mendasar, ini berarti bahwa resolusi kelebihan beban pada 0 akan, secara default, lebih memilih jenis enumerasi daripada jenis numerik. Kami menerima banyak umpan balik bahwa perilaku ini berlawanan.)

  • Mjdan Nj keduanya adalah jenis numerik, dan Mj datang lebih awal dari Nj dalam daftar Byte, SByteShort, UShort, Integer, UIntegerLong, ULong, Decimal, Single, . Double (Catatan. Aturan tentang jenis numerik berguna karena jenis numerik yang ditandatangani dan tidak ditandatangani dari ukuran tertentu hanya memiliki konversi yang mempersempit di antaranya. Aturan di atas memutus dasi antara dua jenis yang mendukung jenis numerik yang lebih "alami". Ini sangat penting ketika melakukan resolusi kelebihan beban pada jenis yang melebar ke jenis numerik yang ditandatangani dan tidak ditandatangani dengan ukuran tertentu, misalnya, literal numerik yang cocok dengan keduanya.)

  • Mj dan Nj mendelegasikan jenis fungsi dan jenis Mj pengembalian lebih spesifik daripada jenis Nj pengembalian If Aj diklasifikasikan sebagai metode lambda, dan Mj atau Nj adalah System.Linq.Expressions.Expression(Of T), maka argumen jenis jenis (dengan asumsi itu adalah jenis delegasi) digantikan untuk jenis yang dibandingkan.

  • Mj identik dengan jenis Aj, dan Nj tidak. (Catatan. Menarik untuk dicatat bahwa aturan sebelumnya sedikit berbeda dari C#, dalam C# tersebut mengharuskan jenis fungsi delegasi memiliki daftar parameter yang identik sebelum membandingkan jenis pengembalian, sementara Visual Basic tidak.)

Generikitas

Anggota M bertekad kurang umum daripada anggota N sebagai berikut:

  1. Jika, untuk setiap pasangan parameter Mj yang cocok dan Nj, Mj kurang atau sama generiknya dibandingkan Nj dengan parameter jenis pada metode , dan setidaknya satu Mj kurang umum sehubungan dengan parameter jenis pada metode .
  2. Jika tidak, jika untuk setiap pasangan parameter Mj yang cocok dan Nj, Mj kurang atau sama generiknya dibandingkan Nj dengan parameter jenis pada jenis, dan setidaknya satu Mj kurang umum sehubungan dengan parameter jenis pada jenis, maka M kurang generik daripada N.

Parameter M dianggap sama generiknya dengan parameter N jika jenisnya Mt dan Nt keduanya merujuk ke parameter jenis atau keduanya tidak merujuk ke parameter jenis. M dianggap kurang umum daripada N jika Mt tidak merujuk ke parameter jenis dan Nt tidak.

Contohnya:

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

Parameter jenis metode ekstensi yang diperbaiki selama kari dianggap sebagai parameter jenis pada jenis, bukan parameter jenis pada metode . Contohnya:

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

Kedalaman generikitas

Anggota M bertekad untuk memiliki kedalaman generik yang lebih besar daripada anggota N jika, untuk setiap pasangan parameter Mj yang cocok dan Nj, Mj memiliki kedalaman generikitas yang lebih Njbesar atau sama dengan , dan setidaknya satu Mj memiliki kedalaman generikitas yang lebih besar. Kedalaman generikitas didefinisikan sebagai berikut:

  • Apa pun selain parameter jenis memiliki kedalaman generik yang lebih besar daripada parameter jenis;

  • Secara rekursif, jenis yang dibangun memiliki kedalaman generik yang lebih besar daripada jenis konstruksi lain (dengan jumlah argumen jenis yang sama) jika setidaknya satu argumen jenis memiliki kedalaman generikitas yang lebih besar dan tidak ada argumen jenis yang memiliki lebih sedikit kedalaman daripada argumen jenis yang sesuai di yang lain.

  • Jenis array memiliki kedalaman generikitas yang lebih besar daripada jenis array lain (dengan jumlah dimensi yang sama) jika jenis elemen pertama memiliki kedalaman generikitas yang lebih besar daripada jenis elemen kedua.

Contohnya:

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

Penerapan ke Daftar Argumen

Metode berlaku untuk sekumpulan argumen jenis, argumen posisi, dan argumen bernama jika metode dapat dipanggil menggunakan daftar argumen. Daftar argumen dicocokkan dengan daftar parameter sebagai berikut:

  1. Pertama, cocokkan setiap argumen posisi untuk daftar parameter metode. Jika ada lebih banyak argumen posisi daripada parameter dan parameter terakhir bukan paramarray, metode ini tidak berlaku. Jika tidak, parameter paramarray diperluas dengan parameter jenis elemen paramarray agar sesuai dengan jumlah argumen posisi. Jika argumen posisi dihilangkan yang akan masuk ke paramarray, metode tidak berlaku.
  2. Selanjutnya, cocokkan setiap argumen bernama dengan parameter dengan nama yang diberikan. Jika salah satu argumen bernama gagal dicocokkan, cocok dengan parameter paramarray, atau cocok dengan argumen yang sudah cocok dengan argumen posisi atau bernama lain, metode tidak berlaku.
  3. Selanjutnya, jika argumen jenis telah ditentukan, argumen tersebut dicocokkan dengan daftar parameter jenis . Jika kedua daftar tidak memiliki jumlah elemen yang sama, metode tidak berlaku, kecuali daftar argumen jenis kosong. Jika daftar argumen jenis kosong, inferensi jenis digunakan untuk mencoba dan menyimpulkan daftar argumen jenis. Jika inferensi jenis gagal, metode ini tidak berlaku. Jika tidak, argumen jenis diisi di tempat parameter jenis dalam tanda tangan. Jika parameter yang belum dicocokkan tidak opsional, metode ini tidak berlaku.
  4. Jika ekspresi argumen tidak secara implisit dapat dikonversi ke jenis parameter yang cocok, maka metode tidak berlaku.
  5. Jika parameter adalah ByRef, dan tidak ada konversi implisit dari jenis parameter ke jenis argumen, maka metode tidak berlaku.
  6. Jika argumen jenis melanggar batasan metode (termasuk argumen jenis yang disimpulkan dari Langkah 3), metode tidak berlaku. Contohnya:
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

Jika ekspresi argumen tunggal cocok dengan parameter paramarray dan jenis ekspresi argumen dapat dikonversi ke jenis parameter paramarray dan jenis elemen paramarray, metode ini berlaku dalam bentuk yang diperluas dan tidak diperluas, dengan dua pengecualian. Jika konversi dari jenis ekspresi argumen ke jenis paramarray dipersempit, maka metode hanya berlaku dalam bentuk yang diperluas. Jika ekspresi argumen adalah harfiah Nothing, maka metode hanya berlaku dalam bentuknya yang tidak terlampaui. Contohnya:

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

Contoh di atas menghasilkan output berikut:

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

Dalam pemanggilan Fpertama dan terakhir , bentuk F normal berlaku karena konversi yang melebar ada dari jenis argumen ke jenis parameter (keduanya berjenis Object()), dan argumen diteruskan sebagai parameter nilai reguler. Dalam pemanggilan kedua dan ketiga, bentuk F normal tidak berlaku karena tidak ada konversi yang melebar dari jenis argumen ke jenis parameter (konversi dari Object ke Object() penyempitan). Namun, bentuk F yang diperluas berlaku, dan satu elemen Object() dibuat oleh pemanggilan. Elemen tunggal array diinisialisasi dengan nilai argumen yang diberikan (yang merupakan referensi ke Object()).

Meneruskan Argumen, dan Memilih Argumen untuk Parameter Opsional

Jika parameter adalah parameter nilai, ekspresi argumen yang cocok harus diklasifikasikan sebagai nilai. Nilai dikonversi ke jenis parameter dan diteruskan sebagai parameter pada waktu proses. Jika parameter adalah parameter referensi dan ekspresi argumen yang cocok diklasifikasikan sebagai variabel yang jenisnya sama dengan parameter, maka referensi ke variabel diteruskan sebagai parameter pada waktu proses.

Jika tidak, jika ekspresi argumen yang cocok diklasifikasikan sebagai variabel, nilai, atau akses properti, maka variabel sementara dari jenis parameter dialokasikan. Sebelum pemanggilan metode pada run time, ekspresi argumen diklasifikasikan ulang sebagai nilai, dikonversi ke jenis parameter, dan ditetapkan ke variabel sementara. Kemudian referensi ke variabel sementara diteruskan sebagai parameter . Setelah pemanggilan metode dievaluasi, jika ekspresi argumen diklasifikasikan sebagai variabel atau akses properti, variabel sementara ditetapkan ke ekspresi variabel atau ekspresi akses properti. Jika ekspresi akses properti tidak Set memiliki aksesor, maka penugasan tidak dilakukan.

Untuk parameter opsional di mana argumen belum disediakan, pengkompilasi memilih argumen seperti yang dijelaskan di bawah ini. Dalam semua kasus, ia menguji terhadap jenis parameter setelah substitusi jenis generik.

  • Jika parameter opsional memiliki atribut System.Runtime.CompilerServices.CallerLineNumber, dan pemanggilan berasal dari lokasi dalam kode sumber, dan literal numerik yang mewakili nomor baris lokasi tersebut memiliki konversi intrinsik ke jenis parameter, maka literal numerik digunakan. Jika pemanggilan mencakup beberapa baris, maka pilihan baris mana yang akan digunakan bergantung pada implementasi.

  • Jika parameter opsional memiliki atribut System.Runtime.CompilerServices.CallerFilePath, dan pemanggilan berasal dari lokasi dalam kode sumber, dan string literal yang mewakili jalur file lokasi tersebut memiliki konversi intrinsik ke jenis parameter, maka literal string digunakan. Format jalur file bergantung pada implementasi.

  • Jika parameter opsional memiliki atribut System.Runtime.CompilerServices.CallerMemberName, dan pemanggilan berada dalam isi anggota jenis atau dalam atribut yang diterapkan ke bagian mana pun dari anggota jenis tersebut, dan string harfiah yang mewakili nama anggota tersebut memiliki konversi intrinsik ke jenis parameter, maka literal string digunakan. Untuk pemanggilan yang merupakan bagian dari pengaktor properti atau penanganan aktivitas kustom, maka nama anggota yang digunakan adalah properti atau peristiwa itu sendiri. Untuk pemanggilan yang merupakan bagian dari operator atau konstruktor, maka nama khusus implementasi digunakan.

Jika tidak ada yang berlaku di atas, maka nilai default parameter opsional digunakan (atau Nothing jika tidak ada nilai default yang disediakan). Dan jika lebih dari satu dari yang di atas berlaku, maka pilihan yang akan digunakan tergantung pada implementasi.

Atribut CallerLineNumber dan CallerFilePath berguna untuk pengelogan. CallerMemberName berguna untuk menerapkan INotifyPropertyChanged. Berikut adalah contohnya.

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

Selain parameter opsional di atas, Microsoft Visual Basic juga mengenali beberapa parameter opsional tambahan jika diimpor dari metadata (yaitu dari referensi DLL):

  • Setelah mengimpor dari metadata, Visual Basic juga memperlakukan parameter <Optional> sebagai indikasi bahwa parameter bersifat opsional: dengan cara ini dimungkinkan untuk mengimpor deklarasi yang memiliki parameter opsional tetapi tidak ada nilai default, meskipun ini tidak dapat diekspresikan menggunakan Optional kata kunci.

  • Jika parameter opsional memiliki atribut Microsoft.VisualBasic.CompilerServices.OptionCompareAttribute, dan harfiah numerik 1 atau 0 memiliki konversi ke jenis parameter, maka pengkompilasi menggunakan sebagai argumen baik literal 1 jika Option Compare Text berlaku, atau literal 0 jika Optional Compare Binary berlaku.

  • Jika parameter opsional memiliki atribut System.Runtime.CompilerServices.IDispatchConstantAttribute, dan memiliki jenis Object, dan tidak menentukan nilai default, maka pengkompilasi menggunakan argumen New System.Runtime.InteropServices.DispatchWrapper(Nothing).

  • Jika parameter opsional memiliki atribut System.Runtime.CompilerServices.IUnknownConstantAttribute, dan memiliki jenis Object, dan tidak menentukan nilai default, maka pengkompilasi menggunakan argumen New System.Runtime.InteropServices.UnknownWrapper(Nothing).

  • Jika parameter opsional memiliki jenis Object, dan tidak menentukan nilai default, maka pengkompilasi menggunakan argumen System.Reflection.Missing.Value.

Metode Bersyarah

Jika metode target yang dirujuk oleh ekspresi pemanggilan adalah subroutine yang bukan anggota antarmuka dan jika metode memiliki satu atau beberapa System.Diagnostics.ConditionalAttribute atribut, evaluasi ekspresi tergantung pada konstanta kompilasi bersyarkat yang ditentukan pada titik tersebut dalam file sumber. Setiap instans atribut menentukan string, yang menamai konstanta kompilasi bersyarkat. Setiap konstanta kompilasi bersyar dievaluasi seolah-olah itu adalah bagian dari pernyataan kompilasi bersyarkat. Jika konstanta mengevaluasi ke True, ekspresi dievaluasi secara normal pada waktu proses. Jika konstanta mengevaluasi ke False, ekspresi tidak dievaluasi sama sekali.

Saat mencari atribut , deklarasi yang paling turunan dari metode yang dapat diambil alih diperiksa.

Nota. Atribut tidak valid pada fungsi atau metode antarmuka dan diabaikan jika ditentukan pada salah satu jenis metode. Dengan demikian, metode bersyarat hanya akan muncul dalam pernyataan pemanggilan.

Ketik Inferensi Argumen

Ketika metode dengan parameter jenis dipanggil tanpa menentukan argumen jenis, ketik inferensi argumen digunakan untuk mencoba dan menyimpulkan argumen jenis untuk panggilan. Ini memungkinkan sintaks yang lebih alami untuk digunakan untuk memanggil metode dengan parameter jenis ketika argumen jenis dapat disimpulkan secara sepele. Misalnya, mengingat deklarasi metode berikut:

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

dimungkinkan Choose untuk memanggil metode tanpa secara eksplisit menentukan argumen jenis:

' 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") 

Melalui inferensi argumen jenis, argumen Integer jenis dan String ditentukan dari argumen ke metode .

Inferensi argumen jenis terjadi sebelum reklasifikasi ekspresi dilakukan pada metode lambda atau penunjuk metode dalam daftar argumen, karena reklassifikasi dari kedua jenis ekspresi tersebut mungkin memerlukan jenis parameter untuk diketahui. Mengingat sekumpulan argumen A1,...,An, sekumpulan parameter P1,...,Pn yang cocok dan sekumpulan parameter T1,...,Tnjenis metode , dependensi antara argumen dan parameter jenis metode pertama kali dikumpulkan sebagai berikut:

  • Jika An harfiah Nothing , tidak ada dependensi yang dihasilkan.

  • Jika An adalah metode lambda dan jenisnya Pn adalah jenis delegasi yang dibangun atau System.Linq.Expressions.Expression(Of T), di mana T adalah jenis delegasi yang dibangun,

  • Jika jenis parameter metode lambda akan disimpulkan dari jenis parameter Pnyang sesuai , dan jenis parameter tergantung pada parameter Tnjenis metode , maka An memiliki dependensi pada Tn.

  • Jika jenis parameter metode lambda ditentukan dan jenis parameter Pn yang sesuai tergantung pada parameter Tnjenis metode , maka Tn memiliki dependensi pada An.

  • Jika jenis Pn pengembalian tergantung pada parameter Tnjenis metode , maka Tn memiliki dependensi pada An.

  • Jika An adalah penunjuk metode dan jenisnya Pn adalah jenis delegasi yang dibangun,

  • Jika jenis Pn pengembalian tergantung pada parameter Tnjenis metode , maka Tn memiliki dependensi pada An.

  • Jika Pn adalah jenis yang dibangun dan jenis Pn tergantung pada parameter Tnjenis metode , maka Tn memiliki dependensi pada An.

  • Jika tidak, tidak ada dependensi yang dihasilkan.

Setelah mengumpulkan dependensi, argumen apa pun yang tidak memiliki dependensi akan dihilangkan. Jika ada parameter jenis metode yang tidak memiliki dependensi keluar (yaitu parameter jenis metode tidak bergantung pada argumen), maka inferensi jenis gagal. Jika tidak, argumen dan parameter jenis metode yang tersisa dikelompokkan ke dalam komponen yang sangat terhubung. Komponen yang sangat terhubung adalah sekumpulan argumen dan parameter jenis metode, di mana elemen apa pun dalam komponen dapat dijangkau melalui dependensi pada elemen lain.

Komponen yang terhubung kuat kemudian diurutkan secara topologis dan diproses dalam urutan topologis:

  • Jika komponen yang sangat diketik hanya berisi satu elemen,

    • Jika elemen telah ditandai selesai, lewati.

    • Jika elemen adalah argumen, tambahkan petunjuk jenis dari argumen ke parameter jenis metode yang bergantung padanya dan tandai elemen sebagai selesai. Jika argumen adalah metode lambda dengan parameter yang masih memerlukan jenis yang disimpulkan, maka simpulkan Object untuk jenis parameter tersebut.

    • Jika elemen adalah parameter jenis metode, maka menyimpulkan parameter jenis metode menjadi jenis dominan di antara petunjuk jenis argumen dan menandai elemen sebagai selesai. Jika petunjuk jenis memiliki batasan elemen array di dalamnya, maka hanya konversi yang valid di antara array dari jenis yang diberikan yang dipertimbangkan (yaitu konversi array kovarian dan intrinsik). Jika petunjuk jenis memiliki batasan argumen umum di dalamnya, maka hanya konversi identitas yang dipertimbangkan. Jika tidak ada jenis dominan yang dapat dipilih, inferensi gagal. Jika ada jenis argumen metode lambda tergantung pada parameter jenis metode ini, jenisnya disebarkan ke metode lambda.

  • Jika komponen yang sangat diketik berisi lebih dari satu elemen, maka komponen berisi siklus.

    • Untuk setiap parameter jenis metode yang merupakan elemen dalam komponen, jika parameter jenis metode bergantung pada argumen yang tidak ditandai selesai, konversikan dependensi tersebut menjadi pernyataan yang akan diperiksa di akhir proses inferensi.

    • Mulai ulang proses inferensi pada titik di mana komponen yang sangat diketik ditentukan.

Jika inferensi jenis berhasil untuk semua parameter jenis metode, maka dependensi apa pun yang diubah menjadi pernyataan akan diperiksa. Pernyataan berhasil jika jenis argumen secara implisit dapat dikonversi ke jenis parameter jenis metode yang disimpulkan. Jika pernyataan gagal, maka ketik inferensi argumen gagal.

Mengingat jenis Ta argumen untuk argumen A dan jenis Tp parameter untuk parameter P, petunjuk jenis dihasilkan sebagai berikut:

  • Jika Tp tidak melibatkan parameter jenis metode apa pun, maka tidak ada petunjuk yang dihasilkan.

  • Jika Tp dan Ta merupakan jenis array dari peringkat yang sama, ganti Ta dan Tp dengan jenis Ta elemen dan Tp dan mulai ulang proses ini dengan pembatasan elemen array.

  • Jika Tp adalah parameter jenis metode, maka Ta ditambahkan sebagai petunjuk jenis dengan batasan saat ini, jika ada.

  • Jika A adalah metode lambda dan Tp merupakan jenis delegasi yang dibangun atau System.Linq.Expressions.Expression(Of T), di mana T merupakan jenis delegasi yang dibangun, untuk setiap jenis parameter metode lambda dan jenis TLTDparameter delegasi yang sesuai, ganti Ta dengan TL dan Tp dengan TD dan mulai ulang proses tanpa batasan. Kemudian, ganti Ta dengan jenis pengembalian metode lambda dan:

    • jika A adalah metode lambda biasa, ganti Tp dengan jenis pengembalian jenis delegasi;
    • jika A adalah metode lambda asinkron dan jenis pengembalian jenis delegasi memiliki formulir Task(Of T) untuk beberapa T, ganti Tp dengan itu T;
    • jika A adalah metode lambda iterator dan jenis pengembalian dari jenis delegasi memiliki formulir IEnumerator(Of T) atau IEnumerable(Of T) untuk beberapa T, ganti Tp dengan yang T.
    • Selanjutnya, mulai ulang proses tanpa batasan.
  • Jika A adalah penunjuk metode dan Tp merupakan jenis delegasi yang dibangun, gunakan jenis Tp parameter untuk menentukan metode mana yang ditunjuk paling berlaku untuk Tp. Jika ada metode yang paling berlaku, ganti Ta dengan jenis pengembalian metode dan Tp dengan jenis pengembalian jenis delegasi dan mulai ulang proses tanpa batasan.

  • Jika tidak, Tp harus merupakan jenis yang dibangun. Mengingat TG, jenis generik dari Tp,

    • Jika Ta adalah TG, mewarisi dari TG, atau mengimplementasikan jenis TG tepat sekali, maka untuk setiap argumen Tax jenis yang cocok dari dan Tpx dari TaTp, ganti Ta dengan Tax dan Tp dengan Tpx dan mulai ulang proses dengan pembatasan argumen generik.

    • Jika tidak, inferensi jenis gagal untuk metode generik.

Keberhasilan inferensi jenis tidak, dalam dan dari dirinya sendiri, menjamin bahwa metode tersebut berlaku.