Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
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:
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.
Verwijder vervolgens alle leden uit de set die niet toegankelijk of niet van toepassing zijn (Sectie van toepassing op argumentlijst) op de argumentenlijst
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) ontspanningsniveauNvan gedelegeerden slechter is dan het laagste ontspanningsniveau van de gedelegeerde inM, dan elimineertNu de set. De ontspanningsniveaus voor gedelegeerden zijn als volgt:Fout delegatieniveau : als de
AddressOfof lambda niet kan worden geconverteerd naar het type gemachtigde.Het beperken van de ontspanning van de gedelegeerde van het retourtype of de parameters -- als het argument is
AddressOfof 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 isTask(Of T)en de conversie van een van de geretourneerde expressies die moetenTworden beperkt; of als het argument een iterator lambda is en het retourtypeIEnumerator(Of T)gedelegeerde ofIEnumerable(Of T)en de conversie van een van de opbrengstoperanden die wordenTbeperkt.Verbreed gedelegeerde ontspanning om te delegeren zonder handtekening - als het type gedelegeerde is
System.DelegateofSystem.MultiCastDelegateSystem.Object.Terugzending of argumenten delegeren ontspanning- als het argument of een lambda met
AddressOfeen 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 argumentAddressOfgeen parameters heeft en het gemachtigdetype parameters heeft.Verbreiding van de ontspanning van het retourtype : als het argument of een lambda met een gedeclareerd retourtype is
AddressOfen 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 isTask(Of T)ofTasken de conversie van alle geretourneerde expressies naarT/Objectrespectievelijk de widening of identiteit met ten minste één widening; of als het argument een iterator lambda is en de gemachtigde isIEnumerator(Of T)of ofIEnumerable(Of T)IEnumeratorofIEnumerableof en de conversie van alle retourexpressies naarT/Objectwidening of identiteit met ten minste één widening.Ontspanning van identiteitsdelegatie : als het argument een
AddressOfof 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() overloadVervolgens 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.)
- Als sommige exemplaarleden van de set alleen beperkte conversies vereisen waarbij het type argumentexpressie is
Object, elimineert u alle andere leden. - 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). - 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 vandaanObjectworden 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 naartoeObjectmoet 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.- Als sommige exemplaarleden van de set alleen beperkte conversies vereisen waarbij het type argumentexpressie is
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 ModuleOpmerking. 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.
Als vervolgens, uitgaande van twee leden van de set
MenN,Mspecifieker is (sectiespecifiekvan leden/typen die een lijst met argumenten hebben gegeven) danNgegeven de lijst met argumenten, elimineertNu 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.Anders past u, gezien twee leden van de set,
MNde volgende regels voor tie-breaking toe, in volgorde:Als
Mer geen parameter ParamArray is, maarNwel, of als beide wel maarMminder argumenten doorgeven aan de parameter ParamArray danNwel, elimineertNu 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 ModuleIn 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.
Als
Mis gedefinieerd in een meer afgeleid type danN, elimineertNu 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 ModuleDeze 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 ModuleAls
MenNuitbreidingsmethoden zijn en het doeltypeMeen klasse of structuur is en het doeltypeNeen interface is, elimineertNu 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 ModuleAls
MenNuitbreidingsmethoden zijn, en het doeltypeMenNidentiek zijn na vervanging van de parameter van het type, en het doeltype van vóór het vervangen vanMde parameter bevat geen typeparameters, maar het doeltypeNwel, heeft minder typeparameters dan het doeltypeN, elimineertNu 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 ModuleVoordat typeargumenten zijn vervangen, als
Mdit minder algemeen is (sectie genericiteit) danN, elimineertNu de set.Als
Mdit geen extensiemethode is enNis, elimineertNu de set.Als
MenNuitbreidingsmethoden zijn enMeerderNzijn gevonden ( Sectie-extensiemethodeverzameling), elimineertNu 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 NamespaceAls 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 ModuleAls
MenNbeide vereiste typedeductie om typeargumenten te produceren, enMniet het dominante typetype voor een van de typeargumenten hoeft te worden bepaald (dat wil bijvoorbeeld elke typeargumenten die zijn afgeleid van één type), maarNwel uit de set is verwijderdN.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.
Als overbelastingsresolutie wordt uitgevoerd om het doel van een expressie voor het maken van gedelegeerden op te lossen van een
AddressOfexpressie, en zowel de gemachtigde alsMfuncties terwijlNhet een subroutine is, elimineertNu de set. Als zowel de gemachtigde alsMsubroutines zijn, terwijl hetNeen functie is, elimineertNu de set.Als
Mer geen optionele parameterstandaarden zijn gebruikt in plaats van expliciete argumenten, maarNdat wel het geval is, elimineertNu de set.Voordat typeargumenten zijn vervangen, als
Mer een grotere mate van genericiteit (sectie genericiteit) is danN, elimineertNu de set.
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
Mjnaar het typeNj. (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.)Ajis de letterlijke waarde0,Mjis een numeriek type enNjis een geïnventariseerd type. (Opmerking. Deze regel is nodig omdat de letterlijke0verbreeding is voor elk geïnventariseerd type. Omdat een geïnventariseerd type breder wordt naar het onderliggende type, betekent dit dat overbelastingsresolutie0standaard de voorkeur geeft aan geïnventariseerd typen boven numerieke typen. We hebben veel feedback ontvangen dat dit gedrag contra-intuïtief was.)MjenNjzowel numerieke typen zijn alsMjeerder danNjin de lijstByte, ,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.)MjenNjzijn functietypen delegeren en het retourtypeMjis specifieker dan het retourtypeNjIfAjis geclassificeerd als een lambda-methode enMjofNjisSystem.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.Mjis identiek aan het typeAjenNjniet. (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 :
- Als voor elk paar overeenkomende parameters
MjenNj,Mjminder of even algemeen is dan met betrekkingNjtot het typeparameters voor de methode, en ten minste éénMjis minder algemeen met betrekking tot het typeparameters voor de methode. - Als voor elk paar overeenkomende parameters en , minder of even algemeen is dan met betrekking
Njtot typeparameters voor het type, en ten minste éénMjis minder algemeen met betrekking tot het type parameters voor het type, is danMminder algemeen danN.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:
- 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.
- 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.
- 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.
- Als de argumentexpressies niet impliciet worden omgezet in de typen parameters die ze overeenkomen, is de methode niet van toepassing.
- 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.
- 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 hetOptionaltrefwoord.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 alsOption Compare Textdat van kracht is, of de letterlijke 0 alsOptional Compare Binarydit van kracht is.Als de optionele parameter het kenmerk
System.Runtime.CompilerServices.IDispatchConstantAttributeheeft en het type heeftObjecten er geen standaardwaarde wordt opgegeven, gebruikt de compiler het argumentNew System.Runtime.InteropServices.DispatchWrapper(Nothing).Als de optionele parameter het kenmerk
System.Runtime.CompilerServices.IUnknownConstantAttributeheeft en het type heeftObjecten er geen standaardwaarde wordt opgegeven, gebruikt de compiler het argumentNew System.Runtime.InteropServices.UnknownWrapper(Nothing).Als de optionele parameter een type
Objectheeft en er geen standaardwaarde wordt opgegeven, gebruikt de compiler het argumentSystem.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
Andit deNothingletterlijke is, worden er geen afhankelijkheden gegenereerd.Als
Anhet een lambda-methode is en het typePneen samengesteld type gedelegeerde is ofSystem.Linq.Expressions.Expression(Of T), waarTis 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 parameterTnvan het methodetype, heeft danAneen afhankelijkheid vanTn.Als het type van een lambda-methodeparameter is opgegeven en het type van de bijbehorende parameter
Pnafhankelijk is van een parameter van het methodetypeTn, is erTneen afhankelijkheid vanAn.Als het retourtype afhankelijk is van
Pneen parameterTnvan het methodetype, is ditTnafhankelijk vanAn.Als
Andit een methodepointer is en het typePneen geconstrueerd gemachtigde type is,Als het retourtype afhankelijk is van
Pneen parameterTnvan het methodetype, is ditTnafhankelijk vanAn.Als
Pndit een samengesteld type is en het type afhankelijk is vanPneen parameterTnvoor het methodetype, is ditTnafhankelijk vanAn.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
Tper geen parameters voor het methodetype zijn betrokken, worden er geen hints gegenereerd.Als
TpenTamatrixtypen van dezelfde rang zijn, vervangtTau deTpelementtypenTaenTpstart u dit proces opnieuw door een beperking voor matrixelementen.Als
Tpdit een parameter voor het methodetype is, wordt dezeTatoegevoegd als een typehint met de huidige beperking, indien van toepassing.Als
Adit een lambda-methode is enTpeen samengesteld gemachtigdetype is ofSystem.Linq.Expressions.Expression(Of T), waarbijThet een samengesteld gemachtigdetype is, voor elk parametertype van de lambda-methode en het bijbehorende parametertypeTDTLvoor gedelegeerden, vervangtTaTLu door enTpTDstart u het proces opnieuw zonder beperking.TaVervang vervolgens door het retourtype van de lambda-methode en:- als
Adit een reguliere lambda-methode is, vervangt u doorTphet retourtype van het type gemachtigde; - als
Ahet een asynchrone lambda-methode is en het retourtype van het type gedelegeerde een formulierTask(Of T)heeft voor sommigeT, vervang dit doorTpdieT; - als
Ahet een iterator lambda-methode is en het retourtype van het type gemachtigde formulierIEnumerator(Of T)heeft ofIEnumerable(Of T)voor sommigeT, vervangTpdit door .T - Start vervolgens het proces opnieuw zonder beperking.
- als
Als
Adit een methode aanwijzer is enTpeen samengesteld type gemachtigde is, gebruikt u de parametertypenTpom te bepalen op welke methode het meest van toepassingTpis. Als er een methode is die het meest van toepassing is, vervangt uTahet retourtype van de methode enTpdoor het retourtype van het gemachtigdetype en start u het proces opnieuw zonder beperking.TpAnders moet dit een geconstrueerd type zijn. GegevenTG, het algemene typeTp,Als
Tadat het isTG, neemt vanTG, of implementeert het typeTGprecies één keer, dan voor elk overeenkomend typeargumentTaxvanTaenTpxvanTp, vervangenTaTaxdoor enTpTpxopnieuw 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.
Visual Basic language spec