Delen via


Oplossing van overbelaste methoden

In de praktijk zijn de regels voor het bepalen van overbelastingsresolutie bedoeld om de overbelasting te vinden die het dichtst bij de werkelijke argumenten ligt. Als er een methode is waarvan de parametertypen overeenkomen met de argumenttypen, is die methode duidelijk de dichtstbijzijnde methode. Aangezien de ene methode dichter is dan een andere methode als alle parametertypen smaller zijn dan (of hetzelfde als) de parametertypen van de andere methode. Als de parameters van geen van beide methoden smaller zijn dan de andere, is er geen manier om te bepalen welke methode dichter bij de argumenten ligt.

Opmerking. Overbelastingsresolutie houdt geen rekening met het verwachte retourtype van de methode.

Houd er ook rekening mee dat vanwege de syntaxis van de benoemde parameter de volgorde van de werkelijke en formele parameters mogelijk niet hetzelfde is.

Op basis van een methodegroep wordt de meest toepasselijke methode in de groep voor een lijst met argumenten bepaald met behulp van de volgende stappen. Als er na het toepassen van een bepaalde stap geen leden in de set blijven staan, treedt er een compilatietijdfout op. Als er slechts één lid in de set blijft, is dat lid het meest van toepassing. De stappen zijn:

  1. Als er geen typeargumenten zijn opgegeven, past u eerst typedeductie toe op methoden met typeparameters. Als typedeductie voor een methode slaagt, worden de argumenten van het afgeleide type gebruikt voor die specifieke methode. Als typedeductie mislukt voor een methode, wordt die methode verwijderd uit de set.

  2. Verwijder vervolgens alle leden uit de set die niet toegankelijk of niet van toepassing zijn (Sectie van toepassing op argumentlijst) op de argumentenlijst

  3. Als een of meer argumenten een of meer lambda-expressies zijn AddressOf , berekent u vervolgens de niveaus van de gedelegeerde-ontspanning voor elk van deze argumenten, zoals hieronder. Als het slechtste (laagste) ontspanningsniveau N van gedelegeerden slechter is dan het laagste ontspanningsniveau van de gedelegeerde in M, dan elimineert N u de set. De ontspanningsniveaus voor gedelegeerden zijn als volgt:

    1. Fout delegatieniveau : als de AddressOf of lambda niet kan worden geconverteerd naar het type gemachtigde.

    2. Het beperken van de ontspanning van de gedelegeerde van het retourtype of de parameters -- als het argument is AddressOf of een lambda met een gedeclareerd type en de conversie van het retourtype van de gemachtigde naar het retourtype van de gemachtigde beperkt is; of als het argument een gewone lambda is en de conversie van een van de retourexpressies naar het retourtype van de gemachtigde beperkt is, of als het argument een asynchroon lambda is en het retourtype gemachtigde is Task(Of T) en de conversie van een van de geretourneerde expressies die moeten T worden beperkt; of als het argument een iterator lambda is en het retourtype IEnumerator(Of T) gedelegeerde of IEnumerable(Of T) en de conversie van een van de opbrengstoperanden die worden T beperkt.

    3. Verbreed gedelegeerde ontspanning om te delegeren zonder handtekening - als het type gedelegeerde is System.Delegate of System.MultiCastDelegateSystem.Object.

    4. Terugzending of argumenten delegeren ontspanning- als het argument of een lambda met AddressOf een gedeclareerd retourtype is en het gemachtigdetype geen retourtype heeft. Of als het argument een lambda is met een of meer retourexpressies en het gemachtigdetype geen retourtype heeft, of als het argument AddressOf geen parameters heeft en het gemachtigdetype parameters heeft.

    5. Verbreiding van de ontspanning van het retourtype : als het argument of een lambda met een gedeclareerd retourtype is AddressOf en er een verbrekingsconversie is van het retourtype naar dat van de gemachtigde; of als het argument een gewone lambda is waarbij de conversie van alle retourexpressies naar het retourtype van de gedelegeerde breder wordt of identiteit met ten minste één widening; of als het argument een asynchroon lambda is en de gemachtigde of de gedelegeerde is Task(Of T) of Task en de conversie van alle geretourneerde expressies naar T/Object respectievelijk de widening of identiteit met ten minste één widening; of als het argument een iterator lambda is en de gemachtigde is IEnumerator(Of T) of of IEnumerable(Of T)IEnumerator of IEnumerable of en de conversie van alle retourexpressies naar T/Object widening of identiteit met ten minste één widening.

    6. Ontspanning van identiteitsdelegatie : als het argument een AddressOf of een lambda is die exact overeenkomt met de gedelegeerde, zonder dat parameters worden uitgebreid of verkleind of verkleind of gesmalen of geretourneerd of geretourneerd. Als sommige leden van de set vervolgens geen narrowing conversies vereisen die van toepassing zijn op een van de argumenten, elimineert u alle leden die dat doen. Voorbeeld:

    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. Vervolgens wordt de verwijdering uitgevoerd op basis van het beperken als volgt. (Houd er rekening mee dat, als optie strikt is ingeschakeld, alle leden die beperken vereisen, al in toepassing zijn beoordeeld (sectie toepasbaarheid op argumentlijst) en verwijderd door stap 2.)

    1. Als sommige exemplaarleden van de set alleen beperkte conversies vereisen waarbij het type argumentexpressie is Object, elimineert u alle andere leden.
    2. Als de set meer dan één lid bevat waarvoor alleen Objecteen beperking is vereist, wordt de doelexpressie voor het aanroepen opnieuw geclassificeerd als een late-gebonden methodetoegang (en er wordt een fout weergegeven als het type met de methodegroep een interface is, of als een van de toepasselijke leden extensieleden zijn).
    3. Als er kandidaten zijn waarvoor alleen het beperken van numerieke letterlijke waarden is vereist, kiest u de meest specifieke voor alle resterende kandidaten door de onderstaande stappen te volgen. Als de winnaar alleen uit numerieke letterlijke waarden vereist, wordt deze gekozen als gevolg van overbelastingsresolutie; anders is het een fout.

    Opmerking. De reden voor deze regel is dat als een programma losjes is getypt (dat wil gezegd, de meeste of alle variabelen worden gedeclareerd als Object), overbelastingsresolutie moeilijk kan zijn wanneer veel conversies vandaan Object worden beperkt. In plaats van dat de overbelastingsresolutie in veel situaties mislukt (waarvoor een sterk type van de argumenten voor de methodeaanroep is vereist), wordt de oplossing van de juiste overbelaste methode die moet worden aangeroepen, uitgesteld tot de uitvoeringstijd. Hierdoor kan de losjes getypte aanroep slagen zonder extra casts. Een ongelukkig neveneffect hiervan is echter dat het uitvoeren van de late gebonden oproep het oproepdoel naartoe Objectmoet gieten. In het geval van een structuurwaarde betekent dit dat de waarde op een tijdelijke waarde moet worden geplaatst. Als de methode die uiteindelijk wordt aangeroepen een veld van de structuur probeert te wijzigen, gaat deze wijziging verloren zodra de methode wordt geretourneerd. Interfaces worden uitgesloten van deze speciale regel, omdat late binding altijd wordt omgezet op basis van de leden van de runtimeklasse of het structuurtype, die mogelijk andere namen hebben dan de leden van de interfaces die ze implementeren.

  5. Als een exemplaarmethode in de set blijft staan waarvoor geen narrowing is vereist, verwijdert u vervolgens alle uitbreidingsmethoden uit de set. Voorbeeld:

    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
    

    Opmerking. Extensiemethoden worden genegeerd als er toepasselijke exemplaarmethoden zijn om te garanderen dat het toevoegen van een import (waardoor nieuwe extensiemethoden mogelijk in het bereik worden gebracht) geen aanroep van een bestaande instantiemethode veroorzaakt om opnieuw te worden gekoppeld aan een extensiemethode. Gezien het brede bereik van sommige uitbreidingsmethoden (dat wil bijvoorbeeld de methoden die zijn gedefinieerd op interfaces en/of typeparameters), is dit een veiligere benadering voor het binden aan extensiemethoden.

  6. Als vervolgens, uitgaande van twee leden van de set M en N, Mspecifieker is (sectiespecifiekvan leden/typen die een lijst met argumenten hebben gegeven) dan N gegeven de lijst met argumenten, elimineert N u de set. Als meer dan één lid in de set blijft en de resterende leden niet even specifiek zijn op basis van de argumentenlijst, treedt er een compilatiefout op.

  7. Anders past u, gezien twee leden van de set, MNde volgende regels voor tie-breaking toe, in volgorde:

    1. Als M er geen parameter ParamArray is, maar N wel, of als beide wel maar M minder argumenten doorgeven aan de parameter ParamArray dan N wel, elimineert N u de set. Voorbeeld:

      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
      

      In het bovenstaande voorbeeld wordt de volgende uitvoer gegenereerd:

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

      Opmerking. Wanneer een klasse een methode declareert met een parameter paramarray, is het niet ongebruikelijk om ook enkele van de uitgebreide formulieren op te nemen als reguliere methoden. Hierdoor is het mogelijk om te voorkomen dat een matrixexemplaren worden toegewezen wanneer een uitgebreide vorm van een methode met een parameter paramarray wordt aangeroepen.

    2. Als M is gedefinieerd in een meer afgeleid type dan N, elimineert N u de set. Voorbeeld:

      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
      

      Deze regel is ook van toepassing op de typen waarop extensiemethoden zijn gedefinieerd. Voorbeeld:

      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. Als M en N uitbreidingsmethoden zijn en het doeltype M een klasse of structuur is en het doeltype N een interface is, elimineert N u de set. Voorbeeld:

      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. Als M en N uitbreidingsmethoden zijn, en het doeltype M en N identiek zijn na vervanging van de parameter van het type, en het doeltype van vóór het vervangen van M de parameter bevat geen typeparameters, maar het doeltype N wel, heeft minder typeparameters dan het doeltype N, elimineert N u de set. Voorbeeld:

      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. Voordat typeargumenten zijn vervangen, als M dit minder algemeen is (sectie genericiteit) dan N, elimineert N u de set.

    6. Als M dit geen extensiemethode is en N is, elimineert N u de set.

    7. Als M en N uitbreidingsmethoden zijn en M eerder N zijn gevonden ( Sectie-extensiemethodeverzameling), elimineert N u de set. Voorbeeld:

      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
      

      Als de extensiemethoden in dezelfde stap zijn gevonden, zijn deze extensiemethoden niet eenduidig. De aanroep kan altijd ondubbelzinnig zijn met behulp van de naam van de standaardmodule met de extensiemethode en het aanroepen van de extensiemethode alsof het een normaal lid was. Voorbeeld:

      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. Als M en N beide vereiste typedeductie om typeargumenten te produceren, en M niet het dominante typetype voor een van de typeargumenten hoeft te worden bepaald (dat wil bijvoorbeeld elke typeargumenten die zijn afgeleid van één type), maar N wel uit de set is verwijderd N .

      Opmerking. Deze regel zorgt ervoor dat overbelastingsresolutie die in eerdere versies is geslaagd (waarbij het uitstellen van meerdere typen voor een typeargument een fout zou veroorzaken), dezelfde resultaten blijven produceren.

    9. Als overbelastingsresolutie wordt uitgevoerd om het doel van een expressie voor het maken van gedelegeerden op te lossen van een AddressOf expressie, en zowel de gemachtigde als M functies terwijl N het een subroutine is, elimineert N u de set. Als zowel de gemachtigde als M subroutines zijn, terwijl het N een functie is, elimineert N u de set.

    10. Als M er geen optionele parameterstandaarden zijn gebruikt in plaats van expliciete argumenten, maar N dat wel het geval is, elimineert N u de set.

    11. Voordat typeargumenten zijn vervangen, als M er een grotere mate van genericiteit (sectie genericiteit) is dan N, elimineert N u de set.

  8. Anders is de aanroep dubbelzinnig en treedt er een compileertijdfout op.

Specificiteit van leden/typen op een lijst met argumenten

Een lid M wordt als even specifiek beschouwd als N, op basis van een argumentlijst A, als hun handtekeningen hetzelfde zijn of als elk parametertype M hetzelfde is als het bijbehorende parametertype in N.

Opmerking. Twee leden kunnen eindigen in een methodegroep met dezelfde handtekening vanwege uitbreidingsmethoden. Twee leden kunnen ook even specifiek zijn, maar niet dezelfde handtekening hebben vanwege typeparameters of paramarray-uitbreiding.

Een lid M wordt beschouwd als specifieker dan N als hun handtekeningen afwijken en ten minste één parametertype M specifieker is dan een parametertype in N, en er is geen parametertype N specifieker dan een parametertype in M. Gezien een paar parameters Mj en Nj dat overeenkomt met een argument Aj, wordt het type Mj beschouwd als specifieker dan het type Nj als een van de volgende voorwaarden waar is:

  • Er bestaat een verbreidingsconversie van het type Mj naar het type Nj. (Opmerking. Omdat parameterstypen worden vergeleken zonder rekening te houden met het werkelijke argument in dit geval, wordt de verbrekingsconversie van constante expressies naar een numeriek type waarin de waarde past, in dit geval niet meegenomen.)

  • Aj is de letterlijke waarde 0, Mj is een numeriek type en Nj is een geïnventariseerd type. (Opmerking. Deze regel is nodig omdat de letterlijke 0 verbreeding is voor elk geïnventariseerd type. Omdat een geïnventariseerd type breder wordt naar het onderliggende type, betekent dit dat overbelastingsresolutie 0 standaard de voorkeur geeft aan geïnventariseerd typen boven numerieke typen. We hebben veel feedback ontvangen dat dit gedrag contra-intuïtief was.)

  • Mjen Nj zowel numerieke typen zijn als Mj eerder dan Nj in de lijst Byte, , SByte, UShortShortIntegerUInteger, , Long, , ULong, Decimal, , . DoubleSingle (Opmerking. De regel over de numerieke typen is handig omdat de ondertekende en niet-ondertekende numerieke typen van een bepaalde grootte alleen beperkte conversies hebben. De bovenstaande regel breekt de koppeling tussen de twee typen ten gunste van het meer 'natuurlijke' numerieke type. Dit is met name belangrijk bij het uitvoeren van een overbelastingsresolutie voor een type dat wordt uitgebreid naar zowel de ondertekende als niet-ondertekende numerieke typen van een bepaalde grootte, bijvoorbeeld een numerieke letterlijke waarde die in beide past.)

  • Mj en Nj zijn functietypen delegeren en het retourtype Mj is specifieker dan het retourtype Nj If Aj is geclassificeerd als een lambda-methode en Mj of Nj is System.Linq.Expressions.Expression(Of T), wordt het typeargument van het type (ervan uitgaande dat het een gemachtigdetype is) vervangen door het type dat wordt vergeleken.

  • Mj is identiek aan het type Ajen Nj niet. (Opmerking. Het is interessant om te weten dat de vorige regel enigszins verschilt van C#, in dat C# vereist dat de gedelegeerde functietypen identieke parameterlijsten hebben voordat de retourtypen worden vergeleken, terwijl Visual Basic dat niet doet.)

Algemeenheid

Als volgt wordt bepaald dat een lid Mminder algemeen is dan een lid N :

  1. Als voor elk paar overeenkomende parameters Mj en Nj, Mj minder of even algemeen is dan met betrekking Nj tot het typeparameters voor de methode, en ten minste één Mj is minder algemeen met betrekking tot het typeparameters voor de methode.
  2. Als voor elk paar overeenkomende parameters en , minder of even algemeen is dan met betrekking Nj tot typeparameters voor het type, en ten minste één Mj is minder algemeen met betrekking tot het type parameters voor het type, is dan M minder algemeen dan N. MjNjMj

Een parameter M wordt beschouwd als even algemeen voor een parameter N als hun typen Mt en Nt beide verwijzen naar typeparameters of beide niet naar typeparameters verwijzen. M wordt beschouwd als minder algemeen dan N als Mt deze niet naar een typeparameter verwijst en Nt wel.

Voorbeeld:

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

Parameters voor extensiemethodetypen die tijdens het kerrieen zijn opgelost, worden beschouwd als typeparameters voor het type, niet van het type parameters voor de methode. Voorbeeld:

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

Diepte van genericiteit

Een lid M wordt bepaald dat er een grotere mate van algemeenheid is dan een lid N als voor elk paar overeenkomende parameters en Njvoor Mj elk paar overeenkomende parameters Mj een grotere of gelijke mate van genericiteit heeft dan Nj, en ten minste één Mj een grotere mate van genericiteit heeft. De diepte van de genericiteit wordt als volgt gedefinieerd:

  • Iets anders dan een typeparameter heeft een grotere mate van genericiteit dan een typeparameter;

  • Recursief heeft een samengesteld type een grotere mate van genericiteit dan een ander samengesteld type (met hetzelfde aantal typeargumenten) als ten minste één typeargument een grotere mate van genericiteit heeft en geen typeargument minder diepte heeft dan het bijbehorende typeargument in het andere.

  • Een matrixtype heeft een grotere mate van genericiteit dan een ander matrixtype (met hetzelfde aantal dimensies) als het elementtype van de eerste groter is dan het elementtype van de tweede.

Voorbeeld:

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

Toepasbaarheid op lijst met argumenten

Een methode is van toepassing op een set van typeargumenten, positieargumenten en benoemde argumenten als de methode kan worden aangeroepen met behulp van de argumentlijsten. De argumentlijsten worden als volgt vergeleken met de parameterlijsten:

  1. Eerst moet u elk positioneel argument vergelijken met de lijst met methodeparameters. Als er meer positionele argumenten zijn dan parameters en de laatste parameter geen paramarray is, is de methode niet van toepassing. Anders wordt de parameter paramarray uitgebreid met parameters van het parametertype paramarray-element dat overeenkomt met het aantal positionele argumenten. Als een positioneel argument wordt weggelaten dat in een paramarray zou worden opgenomen, is de methode niet van toepassing.
  2. Koppel vervolgens elk benoemd argument aan een parameter met de opgegeven naam. Als een van de benoemde argumenten niet overeenkomt, overeenkomt met een parameter paramarray of overeenkomt met een argument dat al overeenkomt met een ander positioneel of benoemd argument, is de methode niet van toepassing.
  3. Als vervolgens typeargumenten zijn opgegeven, worden deze vergeleken met de lijst met typeparameters. Als de twee lijsten niet hetzelfde aantal elementen hebben, is de methode niet van toepassing, tenzij de lijst met typeargumenten leeg is. Als de lijst met typeargumenten leeg is, wordt typedeductie gebruikt om de lijst met typeargumenten af te stellen. Als het type deductie mislukt, is de methode niet van toepassing. Anders worden de typeargumenten ingevuld op de plaats van de typeparameters in de handtekening. Als parameters die niet overeenkomen, niet optioneel zijn, is de methode niet van toepassing.
  4. Als de argumentexpressies niet impliciet worden omgezet in de typen parameters die ze overeenkomen, is de methode niet van toepassing.
  5. Als een parameter ByRef is en er geen impliciete conversie is van het type parameter naar het type van het argument, is de methode niet van toepassing.
  6. Als typeargumenten de beperkingen van de methode schenden (inclusief de uitgestelde typeargumenten uit stap 3), is de methode niet van toepassing. Voorbeeld:
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

Als één argumentexpressie overeenkomt met een parameter paramarray en het type argumentexpressie converteert naar zowel het type van de parameter paramarray als het parametertype paramarray, is de methode van toepassing in zowel de uitgevouwen als niet-uitgevouwen formulieren, met twee uitzonderingen. Als de conversie van het type argumentexpressie naar het type paramarray wordt beperkt, is de methode alleen van toepassing in de uitgevouwen vorm. Als de argumentexpressie de letterlijke expressie Nothingis, is de methode alleen van toepassing in de niet-uitgevouwen vorm. Voorbeeld:

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

In het bovenstaande voorbeeld wordt de volgende uitvoer gegenereerd:

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

In de eerste en laatste aanroepen van Fis de normale vorm van van F toepassing omdat er een widening-conversie bestaat van het argumenttype naar het parametertype (beide van het type Object()) en het argument wordt doorgegeven als een normale waardeparameter. In de tweede en derde aanroep is de normale vorm van F niet van toepassing omdat er geen widening conversie bestaat van het argumenttype naar het parametertype (conversies van Object naar worden Object() beperkt). De uitgevouwen vorm is F echter van toepassing en er wordt een één element Object() gemaakt door de aanroep. Het enige element van de matrix wordt geïnitialiseerd met de opgegeven argumentwaarde (dat zelf een verwijzing naar een Object()is).

Argumenten doorgeven en argumenten kiezen voor optionele parameters

Als een parameter een waardeparameter is, moet de overeenkomende argumentexpressie worden geclassificeerd als een waarde. De waarde wordt geconverteerd naar het type parameter en doorgegeven als de parameter tijdens runtime. Als de parameter een referentieparameter is en de overeenkomende argumentexpressie wordt geclassificeerd als een variabele waarvan het type hetzelfde is als de parameter, wordt een verwijzing naar de variabele doorgegeven als de parameter tijdens runtime.

Als de overeenkomende argumentexpressie anders wordt geclassificeerd als een variabele, waarde of eigenschapstoegang, wordt er een tijdelijke variabele van het type parameter toegewezen. Vóór de aanroep van de methode tijdens runtime wordt de argumentexpressie opnieuw geclassificeerd als een waarde, geconverteerd naar het type parameter en toegewezen aan de tijdelijke variabele. Vervolgens wordt een verwijzing naar de tijdelijke variabele doorgegeven als de parameter. Nadat de methodeaanroep is geëvalueerd, wordt, als de argumentexpressie is geclassificeerd als een variabele of eigenschapstoegang, de tijdelijke variabele toegewezen aan de variabeleexpressie of de eigenschapstoegangsexpressie. Als de eigenschapstoegangsexpressie geen Set toegangsfunctie heeft, wordt de toewijzing niet uitgevoerd.

Voor optionele parameters waarbij geen argument is opgegeven, kiest de compiler argumenten zoals hieronder wordt beschreven. In alle gevallen wordt getest op basis van het parametertype na het vervangen van algemene typen.

  • Als de optionele parameter het kenmerk System.Runtime.CompilerServices.CallerLineNumberheeft en de aanroep afkomstig is van een locatie in de broncode en een numerieke letterlijke waarde die aangeeft dat het regelnummer van die locatie een intrinsieke conversie naar het parametertype heeft, wordt de numerieke letterlijke waarde gebruikt. Als de aanroep meerdere regels omvat, is de keuze welke lijn moet worden gebruikt, afhankelijk van de implementatie.

  • Als de optionele parameter het kenmerk System.Runtime.CompilerServices.CallerFilePathheeft en de aanroep afkomstig is van een locatie in de broncode en een letterlijke tekenreeks die het bestandspad van die locatie vertegenwoordigt, heeft een intrinsieke conversie naar het parametertype, wordt de letterlijke tekenreeks gebruikt. De indeling van het bestandspad is afhankelijk van de implementatie.

  • Als de optionele parameter het kenmerk System.Runtime.CompilerServices.CallerMemberNameheeft en de aanroep zich in de hoofdtekst van een typelid bevindt of in een kenmerk dat is toegepast op een deel van dat typelid, en een letterlijke tekenreeks die die lidnaam vertegenwoordigt, een intrinsieke conversie heeft naar het parametertype, wordt de letterlijke tekenreeks gebruikt. Voor aanroepen die deel uitmaken van eigenschapstoegangsors of aangepaste gebeurtenis-handlers, is de gebruikte lidnaam die van de eigenschap of gebeurtenis zelf. Voor aanroepen die deel uitmaken van een operator of constructor, wordt vervolgens een implementatiespecifieke naam gebruikt.

Als geen van de bovenstaande waarden van toepassing is, wordt de standaardwaarde van de optionele parameter gebruikt (of Nothing als er geen standaardwaarde wordt opgegeven). En als meer dan één van de bovenstaande van toepassing is, is de keuze welke u wilt gebruiken, afhankelijk van de implementatie.

De CallerLineNumber kenmerken en CallerFilePath kenmerken zijn handig voor logboekregistratie. Het CallerMemberName is handig voor de implementatie INotifyPropertyChanged. Hier volgen voorbeelden.

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

Naast de bovenstaande optionele parameters herkent Microsoft Visual Basic ook enkele aanvullende optionele parameters als ze worden geïmporteerd uit metagegevens (bijvoorbeeld vanuit een DLL-verwijzing):

  • Bij het importeren uit metagegevens behandelt Visual Basic ook de parameter <Optional> als indicatie dat de parameter optioneel is: op deze manier is het mogelijk om een declaratie te importeren die een optionele parameter heeft, maar geen standaardwaarde, ook al kan deze niet worden uitgedrukt met behulp van het Optional trefwoord.

  • Als de optionele parameter het kenmerk Microsoft.VisualBasic.CompilerServices.OptionCompareAttributeheeft en de numerieke letterlijke waarde 1 of 0 een conversie naar het parametertype heeft, gebruikt de compiler als argument ofwel de letterlijke 1 als Option Compare Text dat van kracht is, of de letterlijke 0 als Optional Compare Binary dit van kracht is.

  • Als de optionele parameter het kenmerk System.Runtime.CompilerServices.IDispatchConstantAttributeheeft en het type heeft Objecten er geen standaardwaarde wordt opgegeven, gebruikt de compiler het argument New System.Runtime.InteropServices.DispatchWrapper(Nothing).

  • Als de optionele parameter het kenmerk System.Runtime.CompilerServices.IUnknownConstantAttributeheeft en het type heeft Objecten er geen standaardwaarde wordt opgegeven, gebruikt de compiler het argument New System.Runtime.InteropServices.UnknownWrapper(Nothing).

  • Als de optionele parameter een type Objectheeft en er geen standaardwaarde wordt opgegeven, gebruikt de compiler het argument System.Reflection.Missing.Value.

Voorwaardelijke methoden

Als de doelmethode waarnaar een aanroepexpressie verwijst een subroutine is die geen lid is van een interface en als de methode een of meer System.Diagnostics.ConditionalAttribute kenmerken heeft, is de evaluatie van de expressie afhankelijk van de voorwaardelijke compilatieconstanten die op dat punt in het bronbestand zijn gedefinieerd. Elk exemplaar van het kenmerk geeft een tekenreeks op, die een voorwaardelijke compilatieconstante noemt. Elke constante voor voorwaardelijke compilatie wordt geëvalueerd alsof deze deel uitmaakt van een voorwaardelijke compilatie-instructie. Als de constante wordt geëvalueerd True, wordt de expressie normaal geëvalueerd tijdens runtime. Als de constante wordt geëvalueerd False, wordt de expressie helemaal niet geëvalueerd.

Wanneer u op zoek bent naar het kenmerk, wordt de meest afgeleide declaratie van een overschrijfbare methode gecontroleerd.

Opmerking. Het kenmerk is niet geldig voor functies of interfacemethoden en wordt genegeerd als dit is opgegeven voor een van beide soorten methoden. Voorwaardelijke methoden worden dus alleen weergegeven in aanroepinstructies.

Argumentdeductie typen

Wanneer een methode met typeparameters wordt aangeroepen zonder typeargumenten op te geven, wordt typeargumentdeductie gebruikt om argumenten voor de aanroep te proberen en af te stellen. Hierdoor kan een natuurlijkere syntaxis worden gebruikt voor het aanroepen van een methode met typeparameters wanneer de typeargumenten triviaal kunnen worden afgeleid. Bijvoorbeeld, op basis van de volgende methodedeclaratie:

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

het is mogelijk om de Choose methode aan te roepen zonder expliciet een typeargument op te geven:

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

Door middel van typeargumentdeductie worden de typeargumenten Integer bepaald String van de argumenten tot de methode.

Typeargumentdeductie vindt plaats voordat expressieherclassificatie wordt uitgevoerd op lambda-methoden of methodepointers in de lijst met argumenten, omdat herclassificatie van deze twee soorten expressies mogelijk vereist dat het type van de parameter bekend is. Op basis van een set argumenten A1,...,An, een set overeenkomende parameters P1,...,Pn en een set parameters van het methodetype T1,...,Tn, worden de afhankelijkheden tussen de argumenten en parameters van het methodetype eerst als volgt verzameld:

  • Als An dit de Nothing letterlijke is, worden er geen afhankelijkheden gegenereerd.

  • Als An het een lambda-methode is en het type Pn een samengesteld type gedelegeerde is of System.Linq.Expressions.Expression(Of T), waar T is een samengesteld gemachtigdetype,

  • Als het type van een lambda-methodeparameter wordt afgeleid van het type van de corresponderende parameter Pnen het type van de parameter is afhankelijk van een parameter Tnvan het methodetype, heeft dan An een afhankelijkheid van Tn.

  • Als het type van een lambda-methodeparameter is opgegeven en het type van de bijbehorende parameter Pn afhankelijk is van een parameter van het methodetype Tn, is er Tn een afhankelijkheid van An.

  • Als het retourtype afhankelijk is van Pn een parameter Tnvan het methodetype, is dit Tn afhankelijk van An.

  • Als An dit een methodepointer is en het type Pn een geconstrueerd gemachtigde type is,

  • Als het retourtype afhankelijk is van Pn een parameter Tnvan het methodetype, is dit Tn afhankelijk van An.

  • Als Pn dit een samengesteld type is en het type afhankelijk is van Pn een parameter Tnvoor het methodetype, is dit Tn afhankelijk van An.

  • Anders wordt er geen afhankelijkheid gegenereerd.

Nadat u afhankelijkheden hebt verzameld, worden alle argumenten die geen afhankelijkheden hebben, geëlimineerd. Als parameters voor een methodetype geen uitgaande afhankelijkheden hebben (dat wil bijvoorbeeld de parameter van het methodetype niet afhankelijk zijn van een argument), mislukt het type deductie. Anders worden de resterende argumenten en parameters van het methodetype gegroepeerd in sterk verbonden onderdelen. Een sterk verbonden onderdeel is een set argumenten en parameters van het methodetype, waarbij elk element in het onderdeel bereikbaar is via afhankelijkheden van andere elementen.

De sterk verbonden componenten worden vervolgens topologisch gesorteerd en verwerkt in topologische volgorde:

  • Als het sterk getypte onderdeel slechts één element bevat,

    • Als het element al is gemarkeerd als voltooid, slaat u het over.

    • Als het element een argument is, voegt u typehints van het argument toe aan de parameters van het methodetype die hiervan afhankelijk zijn en markeert u het element als voltooid. Als het argument een lambda-methode is met parameters die nog steeds afgeleide typen nodig hebben, moet u de typen van deze parameters afleiden Object .

    • Als het element een parameter voor het methodetype is, moet u de parameter van het methodetype afleiden als het dominante type tussen de hints voor het argumenttype en het element markeren als voltooid. Als een typehint een beperking voor matrixelementen heeft, worden alleen conversies die geldig zijn tussen matrices van het opgegeven type beschouwd (bijvoorbeeld covariant en intrinsieke matrixconversies). Als een typehint een algemene argumentbeperking heeft, worden alleen identiteitsconversies overwogen. Als er geen dominant type kan worden gekozen, mislukt deductie. Als een lambda-methodeargumenttypen afhankelijk zijn van deze parameter van het methodetype, wordt het type doorgegeven aan de lambda-methode.

  • Als het sterk getypte onderdeel meer dan één element bevat, bevat het onderdeel een cyclus.

    • Als voor elke parameter van het methodetype dat een element in het onderdeel is, als de parameter van het methodetype afhankelijk is van een argument dat niet is gemarkeerd als voltooid, converteert u die afhankelijkheid naar een assertie die aan het einde van het deductieproces wordt gecontroleerd.

    • Start het deductieproces opnieuw op het punt waarop de sterk getypte onderdelen zijn bepaald.

Als typedeductie slaagt voor alle parameters van het methodetype, worden eventuele afhankelijkheden die zijn gewijzigd in asserties gecontroleerd. Een bewering slaagt als het type van het argument impliciet wordt omgezet in het afgeleid type van de parameter van het methodetype. Als een assertie mislukt, mislukt deductie van argumenten.

Op basis van een argumenttype Ta voor een argument A en een parametertype Tp voor een parameter Pworden typehints als volgt gegenereerd:

  • Als Tp er geen parameters voor het methodetype zijn betrokken, worden er geen hints gegenereerd.

  • Als Tp en Ta matrixtypen van dezelfde rang zijn, vervangt Ta u de Tp elementtypen Ta en Tp start u dit proces opnieuw door een beperking voor matrixelementen.

  • Als Tp dit een parameter voor het methodetype is, wordt deze Ta toegevoegd als een typehint met de huidige beperking, indien van toepassing.

  • Als A dit een lambda-methode is en Tp een samengesteld gemachtigdetype is of System.Linq.Expressions.Expression(Of T), waarbij T het een samengesteld gemachtigdetype is, voor elk parametertype van de lambda-methode en het bijbehorende parametertype TDTL voor gedelegeerden, vervangt TaTL u door en TpTD start u het proces opnieuw zonder beperking. Ta Vervang vervolgens door het retourtype van de lambda-methode en:

    • als A dit een reguliere lambda-methode is, vervangt u door Tp het retourtype van het type gemachtigde;
    • als A het een asynchrone lambda-methode is en het retourtype van het type gedelegeerde een formulier Task(Of T) heeft voor sommige T, vervang dit door Tp die T;
    • als A het een iterator lambda-methode is en het retourtype van het type gemachtigde formulier IEnumerator(Of T) heeft of IEnumerable(Of T) voor sommigeT, vervang Tp dit door .T
    • Start vervolgens het proces opnieuw zonder beperking.
  • Als A dit een methode aanwijzer is en Tp een samengesteld type gemachtigde is, gebruikt u de parametertypen Tp om te bepalen op welke methode het meest van toepassing Tpis. Als er een methode is die het meest van toepassing is, vervangt u Ta het retourtype van de methode en Tp door het retourtype van het gemachtigdetype en start u het proces opnieuw zonder beperking.

  • Tp Anders moet dit een geconstrueerd type zijn. Gegeven TG, het algemene type Tp,

    • Als Ta dat het is TG, neemt van TG, of implementeert het type TG precies één keer, dan voor elk overeenkomend typeargument Tax van Ta en Tpx van Tp, vervangen TaTax door en TpTpx opnieuw het proces door een algemene argumentbeperking.

    • Anders mislukt het type deductie voor de algemene methode.

Het succes van typedeductie garandeert niet dat de methode van toepassing is.