Lösning för överbelastad metod

I praktiken är reglerna för att fastställa överbelastningsmatchning avsedda att hitta den överlagring som är "närmast" de faktiska argument som anges. Om det finns en metod vars parametertyper matchar argumenttyperna är den metoden uppenbarligen närmast. Bortsett från detta är en metod närmare än en annan om alla dess parametertyper är smalare än (eller samma som) parametertyperna för den andra metoden. Om ingen av metodens parametrar är smalare än den andra finns det inget sätt att avgöra vilken metod som ligger närmare argumenten.

Observera. Överlagringsmatchning tar inte hänsyn till metodens förväntade returtyp.

Observera också att på grund av den namngivna parametersyntaxen kanske ordningen på de faktiska och formella parametrarna inte är densamma.

Med en metodgrupp bestäms den mest tillämpliga metoden i gruppen för en argumentlista med hjälp av följande steg. Om inga medlemmar finns kvar i uppsättningen efter att ett visst steg har tillämpats uppstår ett kompileringsfel. Om endast en medlem finns kvar i uppsättningen är den medlemmen den mest tillämpliga medlemmen. Stegen är:

  1. Om inga typargument har angetts tillämpar du först typinferens på metoder som har typparametrar. Om typinferens lyckas för en metod används argument av härledda typer för den specifika metoden. Om typinferens misslyckas för en metod elimineras den metoden från uppsättningen.

  2. Ta sedan bort alla medlemmar från uppsättningen som är otillgängliga eller inte tillämpliga (avsnitt tillämplig till argumentlista) i argumentlistan

  3. Om ett eller flera argument är AddressOf eller lambda-uttryck beräknar du sedan de delegerade avslappningsnivåerna för varje sådant argument enligt nedan. Om den sämsta (lägsta) delegatavslappningsnivån i N är sämre än den lägsta delegerade avslappningsnivån i Meliminerar N du från uppsättningen. De delegerade avslappningsnivåerna är följande:

    1. Fel på avslappningsnivå för ombud – om AddressOf lambda inte kan konverteras till ombudstypen.

    2. Begränsad delegatavslappning av returtyp eller parametrar – om argumentet är AddressOf eller en lambda med en deklarerad typ och konverteringen från dess returtyp till delegatreturtypen minskar, eller om argumentet är en vanlig lambda och konverteringen från något av dess returuttryck till delegatreturtypen minskar, eller om argumentet är en asynkron lambda och ombudets returtyp är Task(Of T) och konverteringen från något av dess returuttryck till T minskar, eller om argumentet är en iterator lambda och delegatreturtypen IEnumerator(Of T) eller IEnumerable(Of T) och konverteringen från någon av dess avkastningsopernder till T minskar.

    3. Breddning av ombudsavslappning till ombud utan signatur – om ombudstypen är System.Delegate eller System.MultiCastDelegateSystem.Object.

    4. Drop return or arguments delegate relax – om argumentet är AddressOf eller en lambda med en deklarerad returtyp och delegattypen saknar en returtyp, eller om argumentet är en lambda med ett eller flera returuttryck och delegattypen saknar en returtyp, eller om argumentet är AddressOf eller lambda utan parametrar och ombudstypen har parametrar.

    5. Breddning av delegatavslappning av returtyp – om argumentet är AddressOf eller en lambda med en deklarerad returtyp, och det finns en bredare konvertering från dess returtyp till ombudets, eller om argumentet är en vanlig lambda där konverteringen från alla returuttryck till delegatreturtypen breddas eller identiteten med minst en breddning, eller om argumentet är en asynkron lambda och ombudet är Task(Of T) eller Task och konverteringen från alla returuttryck till T/Object breddar eller identiteter med minst en breddning, eller om argumentet är en iterator lambda och ombudet är IEnumerator(Of T) eller IEnumerable(Of T) eller IEnumerator eller IEnumerable och konverteringen från alla returuttryck till T/Object utvidgas eller identiteten med minst en breddning.

    6. Avslappning av identitetsdelegat – om argumentet är en AddressOf eller en lambda som matchar ombudet exakt, utan att utvidga eller minska eller släppa parametrar eller returer eller avkastningar. Om vissa medlemmar i uppsättningen inte kräver att begränsade konverteringar ska tillämpas på något av argumenten eliminerar du sedan alla medlemmar som gör det. Till exempel:

    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. Därefter utförs eliminering baserat på minskning enligt följande. (Observera att om Alternativet strikt är På har alla medlemmar som kräver begränsning redan bedömts vara otillämpbara (avsnitt tillämplighet till argumentlista) och tagits bort i steg 2.)

    1. Om vissa instansmedlemmar i uppsättningen bara kräver begränsade konverteringar där argumentuttryckstypen är Objecteliminerar du alla andra medlemmar.
    2. Om uppsättningen innehåller mer än en medlem som endast kräver en begränsning från Object, omklassificeras anropsmåluttrycket som en sen bindningsmetodåtkomst (och ett fel anges om typen som innehåller metodgruppen är ett gränssnitt eller om någon av de tillämpliga medlemmarna var tilläggsmedlemmar).
    3. Om det finns kandidater som bara kräver att numeriska literaler begränsas väljer du den mest specifika bland alla återstående kandidater enligt stegen nedan. Om vinnaren endast behöver begränsas från numeriska literaler väljs den som ett resultat av överbelastningsmatchning. annars är det ett fel.

    Observera. Motiveringen för den här regeln är att om ett program är löst skrivet (dvs. de flesta eller alla variabler deklareras som Object), kan överlagringsmatchning vara svårt när många konverteringar från Object minskar. I stället för att överbelastningsmatchningen misslyckas i många situationer (kräver stark typning av argumenten till metodanropet) skjuts lösningen av lämplig överbelastad metod för anrop upp till körningstiden. Detta gör att det löst skrivna anropet kan lyckas utan ytterligare gjutningar. En olycklig bieffekt av detta är dock att för att utföra det sena anropet måste anropsmålet gjutas till Object. När det gäller ett strukturvärde innebär det att värdet måste boxas till ett tillfälligt värde. Om metoden som så småningom anropas försöker ändra ett fält i strukturen går den här ändringen förlorad när metoden returneras. Gränssnitt undantas från den här specialregeln eftersom sen bindning alltid matchar medlemmarna i körningsklassen eller strukturtypen, som kan ha andra namn än medlemmarna i de gränssnitt som de implementerar.

  5. Om några instansmetoder finns kvar i uppsättningen som inte kräver en förträngning eliminerar du sedan alla tilläggsmetoder från uppsättningen. Till exempel:

    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
    

    Observera. Tilläggsmetoder ignoreras om det finns tillämpliga instansmetoder för att garantera att tillägg av en import (som kan föra in nya tilläggsmetoder i omfånget) inte leder till att ett anrop på en befintlig instansmetod binds om till en tilläggsmetod. Med tanke på det breda omfånget för vissa tilläggsmetoder (dvs. de som definieras i gränssnitt och/eller typparametrar) är detta en säkrare metod för bindning till tilläggsmetoder.

  6. Om, med tanke på två medlemmar i uppsättningen M och N, M är mer specifik ( avsnittsspecifikhet för medlemmar/typer givet en argumentlista) än N med tanke på argumentlistan, eliminerar du N från uppsättningen. Om fler än en medlem finns kvar i uppsättningen och de återstående medlemmarna inte är lika specifika med tanke på argumentlistan, resulterar ett kompileringsfel.

  7. Annars, med tanke på två medlemmar i uppsättningen, M och N, tillämpar följande regler för bindningsbrott i ordning:

    1. Om M inte har en ParamArray-parameter men N gör det, eller om båda gör det men M skickar färre argument till paramArray-parametern än N vad som gör det, eliminerar N du från uppsättningen. Till exempel:

      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
      

      Exemplet ovan ger följande utdata:

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

      Observera. När en klass deklarerar en metod med en paramarrayparameter är det inte ovanligt att även inkludera några av de expanderade formulären som vanliga metoder. På så sätt är det möjligt att undvika allokeringen av en matrisinstans som inträffar när en expanderad form av en metod med en paramarray-parameter anropas.

    2. Om M definieras i en mer härledd typ än Neliminerar du N från uppsättningen. Till exempel:

      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
      

      Den här regeln gäller även för de typer som tilläggsmetoder definieras på. Till exempel:

      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. Om M och N är tilläggsmetoder och måltypen M för är en klass eller struktur och måltypen N för är ett gränssnitt eliminerar du N från uppsättningen. Till exempel:

      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. Om M och N är tilläggsmetoder, och måltypen för M och N är identiska efter typparameterersättning, och måltypen för före typparameterersättning M inte innehåller typparametrar, men måltypen för N har då färre typparametrar än måltypen Nför , eliminera N från uppsättningen. Till exempel:

      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. Innan typargument har ersatts, om M är mindre generiska (avsnitt generiska) än N, eliminera N från uppsättningen.

    6. Om M inte är en tilläggsmetod och N är eliminerar du N från uppsättningen.

    7. Om M och N är tilläggsmetoder och M hittades före N (Section Extension Method Collection) eliminerar du N från uppsättningen. Till exempel:

      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
      

      Om tilläggsmetoderna hittades i samma steg är dessa tilläggsmetoder tvetydiga. Anropet kan alltid vara tvetydigt med hjälp av namnet på standardmodulen som innehåller tilläggsmetoden och anropar tilläggsmetoden som om den var en vanlig medlem. Till exempel:

      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. Om M och N båda nödvändiga typinferenser för att generera typargument och M inte krävde att den dominerande typen skulle bestämmas för något av dess typargument (dvs. var och en av de typargument som härleds till en enda typ), men N eliminerade N från uppsättningen.

      Observera. Den här regeln säkerställer att överbelastningsmatchning som lyckades i tidigare versioner (där slutsatsdragning av flera typer för ett typargument skulle orsaka ett fel) fortsätter att ge samma resultat.

    9. Om överbelastningsmatchning görs för att matcha målet för ett uttryck för att skapa ombud från ett AddressOf uttryck, och både ombudet och M är funktioner medan N är en underrutin, eliminerar du N från uppsättningen. På samma sätt, om både ombudet och M är subrutiner, medan N är en funktion, eliminerar du N från uppsättningen.

    10. Om M inte använde några valfria parameterstandarder i stället för explicita argument, men N gjorde det, eliminerar N du från uppsättningen.

    11. Innan typargument har ersatts, om M har större djup av generiskitet (section genericity) än N, eliminerar N du sedan från uppsättningen.

  8. Annars är anropet tvetydigt och ett kompileringsfel inträffar.

Specificitet för medlemmar/typer med tanke på en argumentlista

En medlem M anses vara lika specifik som N, med tanke på en argumentlista A, om deras signaturer är desamma eller om varje parametertyp i M är samma som motsvarande parametertyp i N.

Observera. Två medlemmar kan hamna i en metodgrupp med samma signatur på grund av tilläggsmetoder. Två medlemmar kan också vara lika specifika men inte ha samma signatur på grund av typparametrar eller paramarrayexpansion.

En medlem M anses vara mer specifik än N om deras signaturer är olika och minst en parametertyp i M är mer specifik än en parametertyp i N, och ingen parametertyp i N är mer specifik än en parametertyp i M. Med tanke på ett par parametrar Mj och Nj som matchar ett argument Ajanses typen av Mj vara mer specifik än typen av Nj om något av följande villkor är sant:

  • Det finns en bredare konvertering från typen av Mj till typen Nj. (Obs! Eftersom parametertyper jämförs utan hänsyn till det faktiska argumentet i det här fallet beaktas inte den bredare konverteringen från konstanta uttryck till en numerisk typ som värdet passar in i i det här fallet.)

  • Aj är literalen 0, Mj är en numerisk typ och Nj är en uppräknad typ. (Obs! Den här regeln är nödvändig eftersom literalen 0 vidgas till alla uppräknade typer. Eftersom en uppräknad typ vidgas till den underliggande typen innebär det att överbelastningsupplösning på 0 som standard föredrar uppräknade typer framför numeriska typer. Vi fick mycket feedback om att det här beteendet var kontraintuitivt.)

  • Mjoch Nj är båda numeriska typer och Mj kommer tidigare än Nj i listan Byte, , ShortSByte, , IntegerUShort, , UInteger, Long, ULong, Decimal, , Single, Double. (Obs! Regeln om de numeriska typerna är användbar eftersom de signerade och osignerade numeriska typerna av en viss storlek bara har smala konverteringar mellan sig. Ovanstående regel bryter oavgjort mellan de två typerna till förmån för den mer "naturliga" numeriska typen. Detta är särskilt viktigt när du utför överbelastningsmatchning på en typ som vidgas till både signerade och osignerade numeriska typer av en viss storlek, till exempel en numerisk literal som passar in i båda.)

  • Mj och Nj är delegerade funktionstyper Mj och returtypen är mer specifik än returtypen Nj If Aj klassificeras som en lambda-metod, och Mj eller Nj är System.Linq.Expressions.Expression(Of T), ersätts typargumentet för typen (förutsatt att det är en ombudstyp) för den typ som jämförs.

  • Mj är identisk med typen , Ajoch Nj är inte det. (Obs! Det är intressant att notera att den tidigare regeln skiljer sig något från C#, eftersom C# kräver att de delegerade funktionstyperna har identiska parameterlistor innan du jämför returtyper, medan Visual Basic inte gör det.)

Generiskhet

En medlem M är fast besluten att vara mindre generisk än en medlem N enligt följande:

  1. Om, för varje par med matchande parametrar Mj och Nj, Mj är mindre eller lika generiskt än Nj med avseende på typparametrar på metoden, och minst ett Mj är mindre generiskt när det gäller typparametrar på metoden.
  2. Annars, om för varje par med matchande parametrar Mj och Nj, Mj är mindre eller lika generiskt än Nj med avseende på typparametrar på typen, och minst ett Mj är mindre generiskt när det gäller typparametrar på typen, är det mindre M generiskt än N.

En parameter M anses vara lika generisk för en parameter N om deras typer Mt och Nt båda refererar till typparametrar eller båda inte refererar till typparametrar. M anses vara mindre allmänt än N om Mt inte refererar till en typparameter och Nt gör det.

Till exempel:

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

Tilläggsmetodtypparametrar som korrigerades under currying anses vara typparametrar för typen, inte typparametrar på metoden. Till exempel:

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

Generell djup

En medlem M är fast besluten att ha större djup av generiskitet än en medlem N om, för varje par med matchande parametrar Mj och Nj, Mj har större eller lika djup av generiskhet än Nj, och minst en Mj har större djup av generiskitet. Generell djup definieras på följande sätt:

  • Allt annat än en typparameter har större djup av generiskitet än en typparameter.

  • Rekursivt har en konstruerad typ större djup av generiskitet än en annan konstruerad typ (med samma antal typargument) om minst ett typargument har större djup av generiskitet och inget typargument har mindre djup än motsvarande typargument i den andra.

  • En matristyp har större djup av generiskitet än en annan matristyp (med samma antal dimensioner) om elementtypen för den första har större generalitetsdjup än elementtypen för den andra.

Till exempel:

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

Tillämplighet för argumentlista

En metod gäller för en uppsättning typargument, positionsargument och namngivna argument om metoden kan anropas med hjälp av argumentlistorna. Argumentlistorna matchas mot parameterlistorna på följande sätt:

  1. Matcha först varje positionsargument i ordning med listan över metodparametrar. Om det finns fler positionsargument än parametrar och den sista parametern inte är en paramarray är metoden inte tillämplig. Annars expanderas parametern paramarray med parametrar av elementtypen paramarray för att matcha antalet positionsargument. Om ett positionsargument utelämnas som skulle gå in i en paramarray är metoden inte tillämplig.
  2. Matcha sedan varje namngivet argument med en parameter med det angivna namnet. Om ett av de namngivna argumenten inte matchar, matchar en paramarrayparameter eller matchar ett argument som redan matchats med ett annat positionellt eller namngivet argument, är metoden inte tillämplig.
  3. Om typargument har angetts matchas de sedan mot typparameterlistan . Om de två listorna inte har samma antal element är metoden inte tillämplig, såvida inte argumentlistan av typen är tom. Om typargumentlistan är tom används typinferens för att försöka härleda typargumentlistan. Om inferensen av typen misslyckas är metoden inte tillämplig. Annars fylls typargumenten i stället för typparametrarna i signaturen. Om parametrar som inte har matchats inte är valfria är metoden inte tillämplig.
  4. Om argumentuttrycken inte implicit kan konverteras till de typer av parametrar som de matchar är metoden inte tillämplig.
  5. Om en parameter är ByRef och det inte finns någon implicit konvertering från parametertypen till argumentets typ, är metoden inte tillämplig.
  6. Om typargument strider mot metodens begränsningar (inklusive argument av härledd typ från steg 3) är metoden inte tillämplig. Till exempel:
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

Om ett enda argumentuttryck matchar en paramarrayparameter och typen av argumentuttrycket kan konverteras till både typen av parametern paramarray och paramarrayelementtypen, tillämpas metoden i både dess expanderade och oexpandererade former, med två undantag. Om konverteringen från typen av argumentuttrycket till paramarraytypen minskar, är metoden endast tillämplig i dess expanderade form. Om argumentuttrycket är literal Nothinggäller metoden endast i dess oexpandererade form. Till exempel:

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

Exemplet ovan ger följande utdata:

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

I de första och sista anropen av Fgäller den normala formen av F eftersom det finns en bredare konvertering från argumenttypen till parametertypen (båda är av typen Object()), och argumentet skickas som en vanlig värdeparameter. I den andra och tredje anropen är den normala formen inte F tillämplig eftersom det inte finns någon bredare konvertering från argumenttypen till parametertypen (konverteringarna från Object till Object() minskar). Den utökade formen av F är dock tillämplig och ett ett-element Object() skapas av anropet. Det enskilda elementet i matrisen initieras med det angivna argumentvärdet (som i sig är en referens till en Object()).

Skicka argument och välja argument för valfria parametrar

Om en parameter är en värdeparameter måste det matchande argumentuttrycket klassificeras som ett värde. Värdet konverteras till parametertypen och skickas som parameter vid körning. Om parametern är en referensparameter och det matchande argumentuttrycket klassificeras som en variabel vars typ är samma som parametern skickas en referens till variabeln som parameter vid körning.

Om det matchande argumentuttrycket annars klassificeras som en variabel, ett värde eller en egenskapsåtkomst allokeras en tillfällig variabel av parametertypen. Före metodanropet vid körningen omklassificeras argumentuttrycket som ett värde, konverteras till parametertypen och tilldelas till den tillfälliga variabeln. Sedan skickas en referens till den tillfälliga variabeln som parameter. När metodanropet har utvärderats, om argumentuttrycket klassificeras som en variabel eller egenskapsåtkomst, tilldelas den tillfälliga variabeln till variabeluttrycket eller egenskapsåtkomstuttrycket. Om egenskapsåtkomstuttrycket inte har någon Set accessor utförs inte tilldelningen.

För valfria parametrar där ett argument inte har angetts väljer kompilatorn argument enligt beskrivningen nedan. I samtliga fall testas den mot parametertypen efter generisk typersättning.

  • Om den valfria parametern har attributet System.Runtime.CompilerServices.CallerLineNumber, och anropet kommer från en plats i källkoden, och en numerisk literal som representerar platsens radnummer har en inbyggd konvertering till parametertypen, används den numeriska literalen. Om anropet sträcker sig över flera rader är valet av vilken rad som ska användas implementeringsberoende.

  • Om den valfria parametern har attributet System.Runtime.CompilerServices.CallerFilePath, och anropet kommer från en plats i källkoden, och en strängliteral som representerar den platsens filsökväg har en inbyggd konvertering till parametertypen, används strängliteralen. Filsökvägens format är implementeringsberoende.

  • Om den valfria parametern har attributet System.Runtime.CompilerServices.CallerMemberName, och anropet finns i brödtexten för en typmedlem eller i ett attribut som tillämpas på någon del av den typen medlem, och en strängliteral som representerar det medlemsnamnet har en inbyggd konvertering till parametertypen, används strängliteralen. För anrop som ingår i egenskapsåtkomster eller anpassade händelsehanterare är medlemsnamnet som används egenskapen eller själva händelsen. För anrop som ingår i en operator eller konstruktor används ett implementeringsspecifikt namn.

Om inget av ovanstående gäller används den valfria parameterns standardvärde (eller Nothing om inget standardvärde anges). Och om mer än ett av ovanstående gäller är valet som ska användas implementeringsberoende.

Attributen CallerLineNumber och CallerFilePath är användbara för loggning. CallerMemberName Är användbart för att implementera INotifyPropertyChanged. Här är exempel.

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

Förutom de valfria parametrarna ovan identifierar Microsoft Visual Basic även några ytterligare valfria parametrar om de importeras från metadata (dvs. från en DLL-referens):

  • När du importerar från metadata behandlar Visual Basic även parametern <Optional> som ett tecken på att parametern är valfri: på så sätt går det att importera en deklaration som har en valfri parameter men inget standardvärde, även om detta inte kan uttryckas med nyckelordet Optional .

  • Om den valfria parametern har attributet Microsoft.VisualBasic.CompilerServices.OptionCompareAttribute, och den numeriska literalen 1 eller 0 har en konvertering till parametertypen, använder kompilatorn som argument antingen literal 1 om Option Compare Text den är i kraft eller literal 0 om Optional Compare Binary den är i kraft.

  • Om den valfria parametern har attributet System.Runtime.CompilerServices.IDispatchConstantAttribute, och den har typen Object, och den inte anger något standardvärde, använder kompilatorn argumentet New System.Runtime.InteropServices.DispatchWrapper(Nothing).

  • Om den valfria parametern har attributet System.Runtime.CompilerServices.IUnknownConstantAttribute, och den har typen Object, och den inte anger något standardvärde, använder kompilatorn argumentet New System.Runtime.InteropServices.UnknownWrapper(Nothing).

  • Om den valfria parametern har typen Object, och den inte anger något standardvärde, använder kompilatorn argumentet System.Reflection.Missing.Value.

Villkorsstyrda metoder

Om målmetoden som ett anropsuttryck refererar till är en underrutin som inte är medlem i ett gränssnitt och om metoden har ett eller flera System.Diagnostics.ConditionalAttribute attribut, beror utvärderingen av uttrycket på de villkorsstyrda kompileringskonstanterna som definierades vid den tidpunkten i källfilen. Varje instans av attributet anger en sträng som namnger en konstant för villkorlig kompilering. Varje konstant för villkorsstyrd kompilering utvärderas som om den ingick i en villkorsstyrd kompileringsinstrukering. Om konstanten utvärderas till Trueutvärderas uttrycket normalt vid körning. Om konstanten utvärderas till Falseutvärderas inte uttrycket alls.

När du letar efter attributet kontrolleras den mest härledda deklarationen av en övergripande metod.

Observera. Attributet är inte giltigt för funktioner eller gränssnittsmetoder och ignoreras om det anges för någon av metoderna. Därför visas villkorsstyrda metoder endast i anropssatser.

Skriv argumentinferens

När en metod med typparametrar anropas utan att ange typargument används typargumentsinferens för att prova och härleda typargument för anropet. Detta gör att en mer naturlig syntax kan användas för att anropa en metod med typparametrar när typargumenten kan härledas trivialt. Till exempel med följande metoddeklaration:

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

det går att anropa Choose metoden utan att uttryckligen ange ett typargument:

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

Genom typargumentets slutsatsdragning, typargumenten Integer och String bestäms från argumenten till metoden.

Typargumentinferens inträffar innan uttrycksomklassificering utförs på lambda-metoder eller metodpekare i argumentlistan, eftersom omklassificering av dessa två typer av uttryck kan kräva att parametertypen är känd. Med tanke på en uppsättning argument A1,...,An, en uppsättning matchande parametrar P1,...,Pn och en uppsättning parametrar T1,...,Tnför metodtyp samlas först beroendena mellan argumenten och metodtypsparametrarna in på följande sätt:

  • Om An är literalen Nothing genereras inga beroenden.

  • Om An är en lambda-metod och typen av Pn är en konstruerad ombudstyp eller System.Linq.Expressions.Expression(Of T), där T är en konstruerad delegattyp,

  • Om typen av en lambda-metodparameter härleds från typen av motsvarande parameter Pn, och parametertypen är beroende av en metodtypsparameter Tn, har du ett An beroende av Tn.

  • Om typen av en lambda-metodparameter har angetts och vilken typ av motsvarande parameter Pn som är beroende av en parameter av metodtyp Tnhar du ett Tn beroende av An.

  • Om returtypen är beroende av Pn en metodtypsparameter Tnhar du Tn ett beroende av An.

  • Om An är en metodpekare och typen av Pn är en konstruerad ombudstyp,

  • Om returtypen är beroende av Pn en metodtypsparameter Tnhar du Tn ett beroende av An.

  • Om Pn är en konstruerad typ och typen av är beroende av Pn en metodtypsparameter Tnhar du Tn ett beroende av An.

  • Annars genereras inget beroende.

När du har samlat in beroenden elimineras alla argument som inte har några beroenden. Om någon metodtypparametrar inte har några utgående beroenden (dvs. metodtypsparametern inte är beroende av ett argument) misslyckas typinferensen. Annars grupperas de återstående argumenten och metodtypsparametrarna i starkt anslutna komponenter. En starkt ansluten komponent är en uppsättning argument och metodtypsparametrar, där alla element i komponenten kan nås via beroenden för andra element.

De starkt anslutna komponenterna sorteras sedan topologiskt och bearbetas i topologisk ordning:

  • Om den starkt skrivna komponenten endast innehåller ett element,

    • Om elementet redan har markerats som slutfört hoppar du över det.

    • Om elementet är ett argument lägger du till typtips från argumentet till de metodtypsparametrar som är beroende av det och markerar elementet som slutfört. Om argumentet är en lambda-metod med parametrar som fortfarande behöver härledda typer, härleder du Object för typerna av dessa parametrar.

    • Om elementet är en metodtypsparameter kan du dra slutsatsen att parametern för metodtyp är den dominerande typen bland argumenttypens tips och markerar elementet som slutfört. Om ett typtips har en begränsning av matriselementet beaktas endast konverteringar som är giltiga mellan matriser av den angivna typen (dvs. covariant- och inbyggda matriskonverteringar). Om ett typtips har en allmän argumentbegränsning på sig beaktas endast identitetskonverteringar. Om ingen dominerande typ kan väljas misslyckas slutsatsdragningen. Om några lambda-metodargumenttyper är beroende av den här metodtypsparametern sprids typen till lambda-metoden.

  • Om den starkt inskrivna komponenten innehåller mer än ett element innehåller komponenten en cykel.

    • För varje metodtypparameter som är ett element i komponenten, om parametern för metodtyp är beroende av ett argument som inte är markerat som fullständigt, konverterar du det beroendet till ett påstående som ska kontrolleras i slutet av slutsatsdragningsprocessen.

    • Starta om slutsatsdragningsprocessen vid den tidpunkt då de starkt maskinskrivna komponenterna fastställdes.

Om typinferensen lyckas för alla metodtypsparametrar kontrolleras eventuella beroenden som har ändrats till kontroller. En försäkran lyckas om typen av argumentet implicit kan konverteras till den härledda typen av metodtypparameter. Om ett påstående misslyckas kan du skriva argumentinferens.

Med tanke på en argumenttyp Ta för ett argument A och en parametertyp Tp för en parameter Pgenereras typtips på följande sätt:

  • Om Tp inte innehåller några metodtypsparametrar genereras inga tips.

  • Om Tp och Ta är matristyper med samma rangordning ersätter Ta du och Tp med elementtyperna Ta för och Tp startar om den här processen med en begränsning för matriselement.

  • Om Tp är en metodtypparameter läggs den till Ta som ett typtips med den aktuella begränsningen, om någon.

  • Om A är en lambda-metod och Tp är en konstruerad ombudstyp eller System.Linq.Expressions.Expression(Of T), där T är en konstruerad delegattyp, ersätter du med TL och Tp med TD och startar om processen utan begränsning för varje lambda-metodparametertyp TL och motsvarande delegatparametertypTDTa. Ersätt Ta sedan med returtypen för lambda-metoden och:

    • om A är en vanlig lambda-metod ersätter du Tp med returtypen för ombudstypen;
    • if A is async lambda method and the return type of the delegate type has form Task(Of T) for some T, replace Tp with that T;
    • om A är en iterator lambda-metod och returtypen för ombudstypen har formulär IEnumerator(Of T) eller IEnumerable(Of T) för vissa Tersätter du Tp med den T.
    • Starta sedan om processen utan begränsning.
  • Om A är en metodpekare och Tp är en konstruerad ombudstyp använder du parametertyperna Tp för för att avgöra vilken metod som är mest tillämplig för Tp. Om det finns en metod som är mest tillämplig ersätter du Ta med returtypen för metoden och Tp med returtypen för ombudstypen och startar om processen utan begränsning.

  • Annars Tp måste vara en konstruerad typ. Givet TG, den allmänna typen av Tp,

    • Om Ta är TG, ärver från TGeller implementerar typen TG exakt en gång, ersätter TaxTa du med och Tp med Tpx och startar om processen med en allmän argumentbegränsning för varje matchande typargument Tax från Ta och Tpx frånTp.

    • Annars misslyckas typinferensen för den generiska metoden.

Lyckad typinferens garanterar inte i sig att metoden är tillämplig.