Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In der Praxis sollen die Regeln für die Bestimmung der Überladungsauflösung die Überladung finden, die den tatsächlich bereitgestellten Argumenten "am nächsten kommt". Wenn eine Methode vorhanden ist, deren Parametertypen den Argumenttypen entsprechen, ist diese Methode offensichtlich am nächsten. Dies gilt, wenn eine Methode näher als eine andere ist, wenn alle Parametertypen schmaler als (oder identisch mit) den Parametertypen der anderen Methode sind. Wenn keine der Parameter der Methode schmaler als die andere ist, gibt es keine Möglichkeit, zu bestimmen, welche Methode näher an den Argumenten liegt.
Hinweis: Die Überladungsauflösung berücksichtigt nicht den erwarteten Rückgabetyp der Methode.
Beachten Sie außerdem, dass aufgrund der benannten Parametersyntax die Reihenfolge der tatsächlichen und formalen Parameter möglicherweise nicht identisch ist.
Bei einer Methodengruppe wird die am besten geeignete Methode in der Gruppe für eine Argumentliste mithilfe der folgenden Schritte bestimmt. Wenn nach dem Anwenden eines bestimmten Schritts keine Elemente im Satz verbleiben, tritt ein Kompilierungszeitfehler auf. Wenn nur ein Mitglied im Satz verbleibt, ist dieses Mitglied das am besten geeignete Mitglied. Die Schritte sind:
Wenn keine Typargumente angegeben wurden, wenden Sie die Typeinleitung auf alle Methoden an, die Typparameter aufweisen. Wenn die Typableitung für eine Methode erfolgreich ist, werden die abgeleiteten Typargumente für diese bestimmte Methode verwendet. Wenn die Typreferenz für eine Methode fehlschlägt, wird diese Methode aus dem Satz entfernt.
Entfernen Sie als Nächstes alle Elemente aus der Gruppe, auf die nicht zugegriffen werden kann oder nicht anwendbar ist (Section Applicability To Argument List) auf die Argumentliste
Als Nächstes berechnen Sie die Stellvertretungsenentspannungsebenen für jedes Argument wie unten, wenn ein oder mehrere Argumente oder Lambda-Ausdrücke sind
AddressOf. Wenn die schlechteste (niedrigste) DelegierungsentspannungsstufeNschlechter ist als die niedrigste Delegierungsentspannungsstufe inM, dann entfernen SieNden Satz. Die Stellvertretungsentspannungsstufen sind wie folgt:Fehlerdelegat-Entspannungsebene – wenn die
AddressOfOder-Lambda-Funktion nicht in den Delegattyp konvertiert werden kann.Einschränken der Delegierungsentspannung des Rückgabetyps oder der Parameter - wenn das Argument oder eine Lambda-Funktion mit einem deklarierten Typ ist
AddressOfund die Konvertierung vom Rückgabetyp des Stellvertretungstyps in den Rückgabetyp der Stellvertretung eingeschränkt wird oder wenn das Argument eine normale Lambda-Funktion ist und die Konvertierung von einem seiner Rückgabeausdrücke in den Rückgabetyp der Stellvertretung eingeschränkt wird, oder wenn es sich bei dem Argument um eine asynchrone Lambda-Funktion handelt, und der Rückgabetyp der Stellvertretung istTask(Of T)und die Konvertierung von einem der RückgabeausdrückeTin die Eingrenzung erfolgt; oder wenn es sich bei dem Argument um eine Iterator-Lambda-Funktion handelt und der RückgabetypIEnumerator(Of T)der Stellvertretung oderIEnumerable(Of T)die Konvertierung von einem der RückgabeoperndenTin die Eingrenzung erfolgt.Delegieren der Delegierungsentspannung auf Stellvertretung ohne Signatur - wenn der Delegattyp oder
System.DelegateSystem.MultiCastDelegate.System.ObjectDrop return or arguments delegate relaxation - if the argument is
AddressOfor a lambda with a declared return type and the delegate type lack a return type; or if the argument is a lambda with one or more return expressions and the delegate type lack a return type; or if the argument isAddressOfor lambda with no parameters and the delegate type has parameters.Delegieren der Delegierungsentspannung des Rückgabetyps – wenn das Argument oder eine Lambda-Funktion mit einem deklarierten Rückgabetyp ist
AddressOf, und es eine Verbreiterung der Konvertierung vom Rückgabetyp zum Delegaten gibt; oder wenn das Argument eine normale Lambda-Funktion ist, bei der die Konvertierung von allen Rückgabeausdrücken in den Rückgabetyp der Stellvertretung mit mindestens einer Erweiterung erweitert wird oder wenn das Argument eine asynchrone Lambda-Funktion ist und der Delegat oderTask(Of T)Taskund die Konvertierung von allen Rückgabeausdrücken bzwTObject/. derEn Identität wird mit mindestens einer Verbreiterung erweitert, oder wenn es sich bei dem Argument um eine Iterator-Lambda-Funktion handelt und die StellvertretungIEnumerator(Of T)oderIEnumerable(Of T)oderIEnumerableIEnumeratordie Konvertierung von allen RückgabeausdrückenT/Objectauf eine Verbreiterung oder Identität mit mindestens einer Verbreiterung basiert.Entspannung des Identitätsdelegats – wenn das Argument eine
AddressOfoder eine Lambda-Funktion ist, die exakt mit der Stellvertretung übereinstimmt, ohne Parameter zu verbreitern oder einzuschränken oder zurückzugeben oder zurückzugeben. Wenn als Nächstes einige Elemente des Satzes keine Verengungskonvertierungen erfordern, die auf eines der Argumente angewendet werden müssen, entfernen Sie alle Elemente, die dies tun. Beispiel:
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() overloadAls Nächstes erfolgt die Eliminierung auf der Grundlage der folgenden Eingrenzung. (Beachten Sie, dass, wenn Option Strict aktiviert ist, alle Mitglieder, die eine Verengung erfordern, bereits nicht anwendbar (Abschnitt Anwendbarkeit auf Argumentliste) beurteilt und von Schritt 2 entfernt wurden.)
- Wenn einige Instanzenelemente des Satzes nur schmale Konvertierungen erfordern, bei denen der Argumentausdruckstyp ist
Object, entfernen Sie alle anderen Member. - Wenn der Satz mehr als ein Element enthält, für das nur
Objecteine Begrenzung erforderlich ist, wird der Aufrufzielausdruck als spät gebundener Methodenzugriff neu klassifiziert (und ein Fehler wird angegeben, wenn der Typ, der die Methodengruppe enthält, eine Schnittstelle ist oder wenn eines der anwendbaren Member Erweiterungsmember war). - Wenn es Kandidaten gibt, die nur aus numerischen Literalen eingegrenzt werden müssen, wählen Sie anhand der nachstehenden Schritte die spezifischsten Kandidaten aus. Wenn der Gewinner nur eine Verengung von numerischen Literalen erfordert, wird er als Ergebnis der Überladungsauflösung ausgewählt. andernfalls handelt es sich um einen Fehler.
Hinweis: Die Begründung für diese Regel besteht darin, dass eine Überladungsauflösung schwierig sein kann, wenn ein Programm lose typiert ist (d. h. die meisten oder alle Variablen werden als deklariert
Object), kann die Überladungsauflösung schwierig sein, wenn viele KonvertierungenObjecteingeschränkt werden. Anstatt dass die Überladungsauflösung in vielen Situationen fehlschlägt (erfordert eine starke Eingabe der Argumente für den Methodenaufruf), wird die auflösung der entsprechenden überladenen Methode, die aufgerufen werden soll, bis zur Laufzeit verzögert. Dadurch kann der lose typierte Aufruf ohne zusätzliche Umwandlungen erfolgreich ausgeführt werden. Ein unglücklicher Nebeneffekt ist jedoch, dass die Ausführung des verspäteten Anrufs die Umwandlung des Anrufziels erfordertObject. Im Fall eines Strukturwerts bedeutet dies, dass der Wert auf einen temporären Wert gesetzt werden muss. Wenn die Methode schließlich aufgerufen wird, versucht, ein Feld der Struktur zu ändern, geht diese Änderung verloren, sobald die Methode zurückgegeben wird. Schnittstellen werden von dieser speziellen Regel ausgeschlossen, da die späte Bindung immer mit den Membern der Laufzeitklasse oder des Strukturtyps aufgelöst wird, die möglicherweise andere Namen haben als die Member der von ihnen implementierten Schnittstellen.- Wenn einige Instanzenelemente des Satzes nur schmale Konvertierungen erfordern, bei denen der Argumentausdruckstyp ist
Wenn eine Instanzmethode im Satz verbleibt, die keine Eingrenzung erfordern, entfernen Sie dann alle Erweiterungsmethoden aus dem Satz. Beispiel:
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 ModuleHinweis: Erweiterungsmethoden werden ignoriert, wenn es anwendbare Instanzmethoden gibt, um sicherzustellen, dass das Hinzufügen eines Imports (das möglicherweise neue Erweiterungsmethoden in den Bereich bringt) keinen Aufruf einer vorhandenen Instanzmethode zur Neubindung an eine Erweiterungsmethode bewirkt. Angesichts des breiten Umfangs einiger Erweiterungsmethoden (d. h. der auf Schnittstellen und/oder Typparametern definierten) ist dies ein sichererer Ansatz für die Bindung an Erweiterungsmethoden.
Wenn eine der beiden Elemente des Satzes
MalsNMNächstes spezifischer ist (Abschnittsspezifität von Elementen/Typen, die eine Argumentliste angegeben haben), alsNdie Argumentliste angegeben wird, entfernenNSie den Satz. Wenn mehr als ein Element in der Gruppe verbleibt und die verbleibenden Member nicht gleich spezifisch sind, wenn die Argumentliste angegeben ist, führt ein Kompilierungszeitfehler zu einem Fehler.Andernfalls wenden Sie bei zwei Elementen des Satzes
MdieNfolgenden Regeln für die Bindung an, und wenden Sie die folgenden Regeln an, in der folgenden Reihenfolge:Wenn
Mkein ParamArray-Parameter vorhanden ist, aberNbeides, aberMweniger Argumente in den ParamArray-Parameter übergibt alsNdies der Fall ist, entfernen SieNden Satz. Beispiel: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 ModuleIm obigen Beispiel wird die folgende Ausgabe erzeugt:
F(Object, Object()) F(Object, Object, Object()) F(Object, Object, Object()) G(Object)Hinweis: Wenn eine Klasse eine Methode mit einem Paramarray-Parameter deklariert, ist es nicht ungewöhnlich, einige der erweiterten Formen als normale Methoden einzuschließen. Dadurch ist es möglich, die Zuordnung einer Arrayinstanz zu vermeiden, die auftritt, wenn eine erweiterte Form einer Methode mit einem Paramarray-Parameter aufgerufen wird.
Wenn
Min einem abgeleiteten Typ definiert ist alsN, entfernen SieNden Satz. Beispiel: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 ModuleDiese Regel gilt auch für die Typen, für die Erweiterungsmethoden definiert sind. Beispiel:
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 ModuleWenn
MesNsich bei Erweiterungsmethoden und dem Zieltyp umMeine Klasse oder Struktur handelt und der ZieltypNeine Schnittstelle ist, entfernen SieNden Satz. Beispiel: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 ModuleIf
MandNare extension methods, and the target type ofMandNare identisch after type parameter substitution, and the target type ofMbefore type parameter substitution does not contain type parameters but the target type of doesN, then has weniger type parameters than the target type ofN, eliminNfrom the set. Beispiel: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 ModuleEntfernen Sie vor dem Ersetzen von Typargumenten, wenn
Msie weniger generisch (Abschnittsgeneralität) alsNNder Satz ist.Wenn
Mes sich nicht um eine Erweiterungsmethode handelt undNist, entfernen SieNden Satz.Wenn
Mes sich um Erweiterungsmethoden handelt undNMzuvorNgefunden wurde (Section Extension Method Collection), entfernen SieNden Satz. Beispiel: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 NamespaceWenn die Erweiterungsmethoden im selben Schritt gefunden wurden, sind diese Erweiterungsmethoden mehrdeutig. Der Aufruf kann immer unter Verwendung des Namens des Standardmoduls mit der Erweiterungsmethode und dem Aufrufen der Erweiterungsmethode als reguläres Element disambiguiert werden. Beispiel:
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 ModuleIf
MandNboth required typeference to produce type arguments, andMdid not require determining the dominant type for any of its type arguments (d.h. each the type arguments inferred to a single type), butNdid, eliminateNfrom the set.Hinweis: Diese Regel stellt sicher, dass die Überladungsauflösung, die in früheren Versionen erfolgreich war (bei der Ableitung mehrerer Typen für ein Typargument zu einem Fehler führen würde), weiterhin dieselben Ergebnisse erzeugt werden.
Wenn die Überladungsauflösung durchgeführt wird, um das Ziel eines Delegaterstellungsausdrucks aus einem
AddressOfAusdruck zu lösen, und zwar sowohl der DelegatMals auch Funktionen, währendNes sich um eine Unterroutine handelt, entfernen SieNden Satz. Ebenso, wenn sowohl der DelegatMals auch Unterroutinen sind, währendNes sich um eine Funktion handelt, entfernen SieNden Satz.Wenn
Mkeine optionalen Parameter standardmäßig anstelle expliziter Argumente verwendet wurden,Naber dies getan hat, entfernen SieNden Satz.Bevor Typenargumente ersetzt wurden, wenn eine größere Tiefe der Generizität (Abschnittsgeneralität) als
Nvorhanden ist, entfernen SieNden Satz.M
Andernfalls ist der Aufruf mehrdeutig und ein Kompilierungszeitfehler tritt auf.
Spezifität von Elementen/Typen einer Argumentliste
Ein Element M gilt als ebenso spezifisch wie N, wenn eine Argumentliste Aangegeben wird, wenn ihre Signaturen identisch sind oder wenn jeder Parametertyp M identisch ist wie der entsprechende Parametertyp in N.
Hinweis: Zwei Mitglieder können aufgrund von Erweiterungsmethoden in einer Methodengruppe mit derselben Signatur enden. Zwei Elemente können auch gleich spezifisch sein, aber aufgrund von Typparametern oder Paramarrayerweiterungen nicht dieselbe Signatur haben.
Ein Element M wird als spezifischer betrachtet, als N wenn ihre Signaturen unterschiedlich sind und mindestens ein Parametertyp M spezifisch ist als ein Parametertyp in N, und kein Parametertyp N ist spezifischer als ein Parametertyp in M. Bei einem Parameterpaar Mj , Nj das mit einem Argument Ajübereinstimmt, wird der Typ des Typs Mj als spezifisch betrachtet, wenn Nj eine der folgenden Bedingungen zutrifft:
Es gibt eine Erweiterungskonvertierung vom Typ
Mjin den TypNj. (Hinweis. Da Parametertypen ohne Berücksichtigung des tatsächlichen Arguments in diesem Fall verglichen werden, wird die Verbreiterung von Konstantenausdrücken auf einen numerischen Typ, in den der Wert passt, in diesem Fall nicht berücksichtigt.)Ajist das Literal0,Mjist ein numerischer Typ undNjein Aufzählungstyp. (Hinweis. Diese Regel ist erforderlich, da das Literal0auf jeden aufgezählten Typ erweitert wird. Da ein aufgezählter Typ auf den zugrunde liegenden Typ erweitert wird, bedeutet dies, dass die Überladungsauflösung0standardmäßig enumerierte Typen gegenüber numerischen Typen bevorzugt. Wir haben viel Feedback erhalten, dass dieses Verhalten kontraintuitiv war.)MjundNjsind beide numerische Typen undMjkommen früher alsNjin der ListeByte, ,SByte,Short,UShortULongIntegerLongDecimalUIntegerSingle.Double. . (Hinweis. Die Regel zu den numerischen Typen ist nützlich, da die signierten und nicht signierten numerischen Typen einer bestimmten Größe nur schmale Konvertierungen dazwischen aufweisen. Die obige Regel bricht die Verknüpfung zwischen den beiden Typen zugunsten des natürlicheren numerischen Typs auf. Dies ist besonders wichtig bei der Überladungsauflösung für einen Typ, der sowohl auf die signierten als auch nicht signierten numerischen Typen einer bestimmten Größe erweitert wird, z. B. ein numerisches Literal, das in beides passt.)MjundNjsind Delegatfunktionstypen und der RückgabetypMjspezifischer als der Rückgabetyp vonNjIfAjwird als Lambda-Methode klassifiziert undMjoderNjistSystem.Linq.Expressions.Expression(Of T), dann wird das Typargument des Typs (vorausgesetzt, es handelt sich um einen Delegattyp) für den zu vergleichenden Typ ersetzt.Mjist identisch mit dem Typ vonAjundNjist nicht. (Hinweis. Es ist interessant zu beachten, dass sich die vorherige Regel geringfügig von C# unterscheidet, in diesem C# erfordert, dass die Stellvertretungsfunktionstypen identische Parameterlisten haben, bevor Rückgabetypen verglichen werden, während Visual Basic nicht.)
Generizität
Ein Element M wird als weniger generisch als ein Element N wie folgt bestimmt:
- Wenn für jedes Paar übereinstimmende Parameter
MjkleinerNjMjoder gleich generisch ist alsNjbei Typparametern für die Methode, und mindestens einsMjist im Hinblick auf Typparameter für die Methode weniger generisch. - Andernfalls, wenn für jedes Paar übereinstimmende Parameter und , kleiner oder gleich generisch als
Njin Bezug auf Typparameter für den Typ, und mindestens eineMjist weniger generisch in Bezug auf Typparameter für den Typ des Typs, dannMist weniger generisch alsN.MjNjMj
Ein Parameter M gilt als gleichermaßen generisch für einen Parameter N , wenn seine Typen Mt und Nt beide auf Typparameter verweisen oder beide nicht auf Typparameter verweisen.
M wird als weniger generisch betrachtet als N wenn Mt er nicht auf einen Typparameter verweist und Nt dies tut.
Beispiel:
Class C1(Of T)
Sub S1(Of U)(x As U, y As T)
End Sub
Sub S1(Of U)(x As U, y As U)
End Sub
Sub S2(x As Integer, y As T)
End Sub
Sub S2(x As T, y As T)
End Sub
End Class
Module Test
Sub Main()
Dim x As C1(Of Integer) = New C1(Of Integer)
x.S1(10, 10) ' Calls S1(U, T)
x.S2(10, 10) ' Calls S2(Integer, T)
End Sub
End Module
Parameter des Erweiterungsmethodetyps, die während der Ausführung des Fehlers behoben wurden, gelten als Typparameter für den Typ, nicht als Typparameter für die Methode. Beispiel:
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
Tiefe der Generizität
Ein Element wird bestimmt, dass eine größere Tiefe der Generizität als ein Element NM vorhanden ist, wenn für jedes Paar übereinstimmende Parameter Mj und Njeine Mj größere oder gleiche Tiefe der Generizität als Nj, und mindestens ein Mj Element eine größere Tiefe der Generizität aufweist. Die Tiefe der Generizität wird wie folgt definiert:
Alles andere als ein Typparameter hat eine größere Tiefe der Generizität als ein Typparameter;
Rekursiv weist ein konstruierter Typ eine größere Tiefe der Generizität auf als ein anderer konstruierter Typ (mit derselben Anzahl von Typargumenten), wenn mindestens ein Typargument eine größere Tiefe von Generizität aufweist und kein Typargument weniger Tiefe als das entsprechende Typargument in der anderen hat.
Ein Arraytyp hat eine größere Tiefe der Generizität als ein anderer Arraytyp (mit derselben Anzahl dimensionen), wenn der Elementtyp des ersten eine größere Tiefe der Generizität aufweist als der Elementtyp des zweiten.
Beispiel:
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
Anwendbarkeit auf Argumentliste
Eine Methode gilt für eine Reihe von Typargumenten, Positionsargumenten und benannten Argumenten, wenn die Methode mithilfe der Argumentlisten aufgerufen werden kann. Die Argumentlisten werden wie folgt mit den Parameterlisten abgeglichen:
- Stimmen Sie zunächst jedem Positionsargument zu, um der Liste der Methodenparameter zu entsprechen. Wenn es mehr Positionsargumente als Parameter gibt und der letzte Parameter kein Paramarray ist, ist die Methode nicht anwendbar. Andernfalls wird der Paramarray-Parameter mit Parametern des Paramarray-Elementtyps erweitert, um der Anzahl der Positionsargumente zu entsprechen. Wenn ein Positionsargument ausgelassen wird, das in einen Paramarray gehen würde, ist die Methode nicht anwendbar.
- Stimmen Sie als Nächstes jedem benannten Argument einen Parameter mit dem angegebenen Namen zu. Wenn eines der benannten Argumente nicht übereinstimmen kann, mit einem Paramarray-Parameter übereinstimmt oder mit einem Argument übereinstimmt, das bereits mit einem anderen Positions- oder benannten Argument übereinstimmt, gilt die Methode nicht.
- Wenn als Nächstes Typargumente angegeben wurden, werden sie mit der Typparameterliste abgeglichen. Wenn die beiden Listen nicht über dieselbe Anzahl von Elementen verfügen, gilt die Methode nicht, es sei denn, die Typargumentliste ist leer. Wenn die Typargumentliste leer ist, wird die Typreferenz verwendet, um die Typargumentliste zu testen und zu ableiten. Wenn der Typ inferencing fehlschlägt, gilt die Methode nicht. Andernfalls werden die Typargumente anstelle der Typparameter in der Signatur ausgefüllt. Wenn parameter, die nicht übereinstimmen, nicht optional sind, ist die Methode nicht anwendbar.
- Wenn die Argumentausdrücke nicht implizit in die Typen der übereinstimmenden Parameter konvertierbar sind, ist die Methode nicht anwendbar.
- Wenn ein Parameter ByRef ist und keine implizite Konvertierung vom Typ des Parameters in den Typ des Arguments vorhanden ist, ist die Methode nicht anwendbar.
- Wenn Typargumente gegen die Einschränkungen der Methode verstoßen (einschließlich der abgeleiteten Typargumente aus Schritt 3), ist die Methode nicht anwendbar. Beispiel:
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
Wenn ein einzelner Argumentausdruck mit einem Paramarray-Parameter übereinstimmt und der Typ des Argumentausdrucks sowohl in den Typ des Paramarrayparameters als auch auf den Paramarray-Elementtyp konvertiert wird, gilt die Methode sowohl in erweiterten als auch in nicht erweiterten Formen mit zwei Ausnahmen. Wenn die Konvertierung vom Typ des Argumentausdrucks in den Paramarraytyp schmal ist, gilt die Methode nur in seiner erweiterten Form. Wenn der Argumentausdruck das Literal Nothingist, gilt die Methode nur in seiner nicht erweiterten Form. Beispiel:
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
Im obigen Beispiel wird die folgende Ausgabe erzeugt:
System.Int32 System.String System.Double
System.Object[]
System.Object[]
System.Int32 System.String System.Double
In den ersten und letzten Aufrufen von Fist die normale Form anwendbar F , da eine Erweiterungskonvertierung vom Argumenttyp in den Parametertyp (beide vom Typ Object()) vorhanden ist und das Argument als normaler Wertparameter übergeben wird. In den zweiten und dritten Aufrufen ist die normale Form nicht F anwendbar, da keine Erweiterungskonvertierung vom Argumenttyp in den Parametertyp vorhanden ist (Konvertierungen von Object zu Object() verengen). Die erweiterte Form von F ist jedoch anwendbar, und ein Eins-Element Object() wird durch den Aufruf erstellt. Das einzelne Element des Arrays wird mit dem angegebenen Argumentwert initialisiert (was selbst ein Verweis auf einen Object()).
Übergeben von Argumenten und Auswählen von Argumenten für optionale Parameter
Wenn ein Parameter ein Wertparameter ist, muss der übereinstimmende Argumentausdruck als Wert klassifiziert werden. Der Wert wird in den Typ des Parameters konvertiert und zur Laufzeit als Parameter übergeben. Wenn der Parameter ein Verweisparameter ist und der übereinstimmende Argumentausdruck als Variable klassifiziert wird, deren Typ dem Parameter entspricht, wird ein Verweis auf die Variable zur Laufzeit als Parameter übergeben.
Andernfalls wird eine temporäre Variable des Typs des Parameters zugewiesen, wenn der übereinstimmende Argumentausdruck als Variable, Wert oder Eigenschaftszugriff klassifiziert wird. Vor dem Aufruf der Methode zur Laufzeit wird der Argumentausdruck als Wert neu klassifiziert, in den Typ des Parameters konvertiert und der temporären Variablen zugewiesen. Anschließend wird ein Verweis auf die temporäre Variable als Parameter übergeben. Nachdem der Methodenaufruf ausgewertet wurde, wird die temporäre Variable dem Variablenausdruck oder dem Eigenschaftszugriff zugewiesen, wenn der Argumentausdruck als Variable oder Eigenschaftszugriff klassifiziert wird. Wenn der Eigenschaftszugriffsausdruck keinen Set Accessor hat, wird die Zuweisung nicht ausgeführt.
Bei optionalen Parametern, bei denen kein Argument angegeben wurde, wählt der Compiler argumente aus, wie unten beschrieben. In allen Fällen wird nach der Ersetzung des generischen Typs anhand des Parametertyps getestet.
Wenn der optionale Parameter das Attribut
System.Runtime.CompilerServices.CallerLineNumberaufweist und der Aufruf von einer Stelle im Quellcode stammt und ein numerisches Literal, das die Zeilennummer dieser Position darstellt, eine systeminterne Konvertierung in den Parametertyp aufweist, wird das numerische Literal verwendet. Wenn der Aufruf mehrere Zeilen umfasst, ist die Auswahl, welche Zeile verwendet werden soll, implementierungsabhängig.Wenn der optionale Parameter das Attribut
System.Runtime.CompilerServices.CallerFilePathaufweist und der Aufruf von einem Speicherort im Quellcode stammt und ein Zeichenfolgenliteral, das den Dateipfad dieses Speicherorts darstellt, eine systeminterne Konvertierung in den Parametertyp aufweist, wird das Zeichenfolgenliteral verwendet. Das Format des Dateipfads ist von der Implementierung abhängig.Wenn der optionale Parameter das Attribut
System.Runtime.CompilerServices.CallerMemberNameaufweist und sich der Aufruf innerhalb des Textkörpers eines Typelements oder in einem Attribut befindet, das auf einen Teil dieses Typelements angewendet wird, und ein Zeichenfolgenliteral, das diesen Membernamen darstellt, eine systeminterne Konvertierung in den Parametertyp aufweist, wird das Zeichenfolgenliteral verwendet. Bei Aufrufen, die Teil von Eigenschaftenaccessoren oder benutzerdefinierten Ereignishandlern sind, ist der verwendete Membername der Eigenschaft oder des Ereignisses selbst. Für Aufrufe, die Teil eines Operators oder Konstruktors sind, wird ein implementierungsspezifischer Name verwendet.
Wenn keines der oben genannten Werte zutrifft, wird der Standardwert des optionalen Parameters verwendet (oder Nothing wenn kein Standardwert angegeben wird). Und wenn mehr als eine der oben genannten Anwendung zutrifft, ist die Auswahl, von der sie verwendet werden soll, von der Implementierung abhängig.
Die CallerLineNumber Attribute sind CallerFilePath nützlich für die Protokollierung. Dies CallerMemberName ist nützlich für die Implementierung INotifyPropertyChanged. Im Folgenden finden Sie Beispiele.
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
Zusätzlich zu den oben genannten optionalen Parametern erkennt Microsoft Visual Basic auch einige zusätzliche optionale Parameter, wenn sie aus Metadaten importiert werden (d. h. aus einem DLL-Verweis):
Beim Importieren aus Metadaten behandelt Visual Basic den Parameter auch als Hinweis darauf, dass der Parameter
<Optional>optional ist: Auf diese Weise ist es möglich, eine Deklaration zu importieren, die einen optionalen Parameter, aber keinen Standardwert aufweist, auch wenn dies nicht mithilfe desOptionalSchlüsselworts ausgedrückt werden kann.Wenn der optionale Parameter das Attribut
Microsoft.VisualBasic.CompilerServices.OptionCompareAttributeaufweist, und das numerische Literal 1 oder 0 eine Konvertierung in den Parametertyp hat, verwendet der Compiler entweder als Argument entweder das Literal 1, wennOption Compare Textdies wirksam ist, oder das Literal 0, wennOptional Compare Binarydies wirksam ist.Wenn der optionale Parameter über das Attribut
System.Runtime.CompilerServices.IDispatchConstantAttributeverfügt und einen TypObjectaufweist und keinen Standardwert angibt, verwendet der Compiler das ArgumentNew System.Runtime.InteropServices.DispatchWrapper(Nothing).Wenn der optionale Parameter über das Attribut
System.Runtime.CompilerServices.IUnknownConstantAttributeverfügt und einen TypObjectaufweist und keinen Standardwert angibt, verwendet der Compiler das ArgumentNew System.Runtime.InteropServices.UnknownWrapper(Nothing).Wenn der optionale Parameter Typ
Objectaufweist und kein Standardwert angegeben wird, verwendet der Compiler das ArgumentSystem.Reflection.Missing.Value.
Bedingte Methoden
Wenn die Zielmethode, auf die ein Aufrufausdruck verweist, eine Unterroutine ist, die kein Element einer Schnittstelle ist und wenn die Methode über mindestens ein System.Diagnostics.ConditionalAttribute Attribut verfügt, hängt die Auswertung des Ausdrucks von den an diesem Punkt in der Quelldatei definierten bedingten Kompilierungskonstanten ab. Jede Instanz des Attributs gibt eine Zeichenfolge an, die eine bedingte Kompilierungskonstante benennt. Jede konstante bedingte Kompilierung wird ausgewertet, als ob sie Teil einer bedingungsbedingten Kompilierungsanweisung wäre. Wenn die Konstante ausgewertet wird True, wird der Ausdruck zur Laufzeit normal ausgewertet. Wenn die Konstante ausgewertet wird False, wird der Ausdruck überhaupt nicht ausgewertet.
Bei der Suche nach dem Attribut wird die abgeleitete Deklaration einer überschreibbaren Methode überprüft.
Hinweis: Das Attribut ist für Funktionen oder Schnittstellenmethoden nicht gültig und wird ignoriert, wenn es für eine der Methodenarten angegeben ist. Daher werden bedingte Methoden nur in Aufrufanweisungen angezeigt.
Typargument-Ableitung
Wenn eine Methode mit Typparametern ohne Angabe von Typargumenten aufgerufen wird, wird typargumentinference verwendet, um Typenargumente für den Aufruf zu versuchen und zu ableiten. Dadurch kann eine natürlichere Syntax zum Aufrufen einer Methode mit Typparametern verwendet werden, wenn die Typargumente trivial abgeleitet werden können. Beispiel: Bei der folgenden Methodendeklaration:
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
Es ist möglich, die Choose Methode aufzurufen, ohne explizit ein Typargument anzugeben:
' 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")
Durch Typargument-Ableitung werden die Typargumente IntegerString und von den Argumenten zur Methode bestimmt.
Typargumenteinschluss tritt auf , bevor die Neuklassifizierung des Ausdrucks für Lambdamethoden oder Methodenzeiger in der Argumentliste ausgeführt wird, da eine Neuklassifizierung dieser beiden Arten von Ausdrücken möglicherweise den Typ des Parameters erfordert, dass er bekannt ist. Bei einem Satz von Argumenten A1,...,An, einer Reihe übereinstimmener Parameter P1,...,Pn und einer Reihe von Methodentypparametern T1,...,Tnwerden die Abhängigkeiten zwischen den Argumenten und Methodentypparametern zuerst wie folgt erfasst:
Wenn
Anes sich um dasNothingLiteral handelt, werden keine Abhängigkeiten generiert.If
Anis a lambda method and the type ofPnis a constructed delegate type orSystem.Linq.Expressions.Expression(Of T), whereTis a constructed delegate type,Wenn der Typ eines Lambda-Methodenparameters vom Typ des entsprechenden Parameters
Pnabgeleitet wird und der Typ des Parameters von einem MethodentypparameterTnabhängt, hat diesAneine Abhängigkeit vonTn.Wenn der Typ eines Lambda-Methodenparameters angegeben wird und der Typ des entsprechenden Parameters
Pnvon einem MethodentypparameterTnabhängt, hat diesTneine Abhängigkeit vonAn.Wenn der Rückgabetyp von
Pneinem MethodentypparameterTnabhängt, hat diesTneine Abhängigkeit vonAn.If
Anis a method pointer and the type ofPnis a constructed delegate type,Wenn der Rückgabetyp von
Pneinem MethodentypparameterTnabhängt, hat diesTneine Abhängigkeit vonAn.Wenn
Pnes sich um einen konstruierten Typ handelt und der Typ von abhängigkeit vonPneinem MethodentypparameterTnist, hat diesTneine Abhängigkeit vonAn.Andernfalls wird keine Abhängigkeit generiert.
Nach dem Sammeln von Abhängigkeiten werden alle Argumente ohne Abhängigkeiten entfernt. Wenn methodentypparameter keine ausgehenden Abhängigkeiten aufweisen (d. h. der Methodentypparameter hängt nicht von einem Argument ab), schlägt die Typausleitung fehl. Andernfalls werden die verbleibenden Argumente und Methodentypparameter in stark verbundene Komponenten gruppiert. Eine stark verbundene Komponente ist eine Reihe von Argumenten und Methodentypparametern, bei denen jedes Element in der Komponente über Abhängigkeiten von anderen Elementen erreichbar ist.
Die stark verbundenen Komponenten werden dann toplogisch sortiert und in topologischer Reihenfolge verarbeitet:
Wenn die stark typierte Komponente nur ein Element enthält,
Wenn das Element bereits als abgeschlossen markiert wurde, überspringen Sie es.
Wenn das Element ein Argument ist, fügen Sie Typhinweise aus dem Argument zu den Methodentypparametern hinzu, die davon abhängig sind, und markieren Sie das Element als abgeschlossen. Wenn es sich bei dem Argument um eine Lambda-Methode mit Parametern handelt, die weiterhin abgeleitete Typen benötigen, wird für die Typen dieser Parameter abgeleitet
Object.Wenn es sich bei dem Element um einen Methodentypparameter handelt, wird der Methodentypparameter als dominanter Typ unter den Argumenttyphinweisen verwendet und das Element als abgeschlossen gekennzeichnet. Wenn ein Typhinweis eine Arrayelementeinschränkung enthält, werden nur Konvertierungen berücksichtigt, die zwischen Arrays des angegebenen Typs gültig sind (z. B. kovariante und systeminterne Arraykonvertierungen). Wenn ein Typhinweis eine generische Argumenteinschränkung enthält, werden nur Identitätskonvertierungen berücksichtigt. Wenn kein dominanter Typ ausgewählt werden kann, schlägt die Ableitung fehl. Wenn lambda-Methodenargumenttypen von diesem Methodentypparameter abhängen, wird der Typ an die Lambda-Methode weitergegeben.
Wenn die stark typierte Komponente mehrere Elemente enthält, enthält die Komponente einen Zyklus.
Wenn der Methodentypparameter für jeden Methodentypparameter, der ein Element in der Komponente ist, von einem Argument abhängig ist, das nicht als abgeschlossen gekennzeichnet ist, konvertieren Sie diese Abhängigkeit in eine Assertion, die am Ende des Rückschlussprozesses überprüft wird.
Starten Sie den Ableitungsprozess an dem Punkt neu, an dem die stark typierten Komponenten ermittelt wurden.
Wenn die Typeinleitung für alle Methodentypparameter erfolgreich verläuft, werden alle Abhängigkeiten überprüft, die in Assertionen geändert wurden. Eine Assertion ist erfolgreich, wenn der Typ des Arguments implizit in den abgeleiteten Typ des Methodentypparameters konvertierbar ist. Wenn eine Assertion fehlschlägt, schlägt die Typargumentleitung fehl.
Bei einem Argumenttyp Ta für ein Argument A und einem Parametertyp Tp für einen Parameter Pwerden Typenhinweise wie folgt generiert:
Wenn
Tpkeine Methodentypparameter einbezogen werden, werden keine Hinweise generiert.Wenn
TpesTasich um Arraytypen desselben Rangs handelt, ersetzenTaSie diesen Vorgang durchTpdie ElementtypenTa, undTpstarten Sie diesen Vorgang mit einer Arrayelementeinschränkung neu.Wenn
Tpes sich um einen Methodentypparameter handelt, wird dieserTabei Bedarf als Typhinweis mit der aktuellen Einschränkung hinzugefügt.Wenn
Aes sich um eine Lambda-Methode handelt undTpein konstruierter DelegattypSystem.Linq.Expressions.Expression(Of T)oder , wobeiTes sich um einen konstruierten Delegatentyp handelt, für jeden Lambda-MethodenparametertypTLund den entsprechenden StellvertretungsparametertypTDersetzenTaTLundTpdurchTDden Prozess ohne Einschränkung neu starten. Ersetzen SieTadann durch den Rückgabetyp der Lambda-Methode und:- wenn
Aes sich um eine normale Lambda-Methode handelt, ersetzen SieTpsie durch den Rückgabetyp des Delegatentyps; - if
Ais ansync lambda method and the return type of the delegate type has formTask(Of T)for someT, replaceTpwith thatT; - if
Ais an iterator lambda method and the return type of the delegate type has formIEnumerator(Of T)orIEnumerable(Of T)for someT, replaceTpwith thatT. - Starten Sie als Nächstes den Prozess ohne Einschränkung neu.
- wenn
Wenn
Aes sich um einen Methodenzeiger handelt undTpein konstruierter Delegattyp ist, verwenden Sie die Parametertypen,Tpum zu bestimmen, auf welche Methode verwiesen wirdTp. Wenn es eine Methode gibt, die am besten geeignet ist, ersetzen SieTadurch den Rückgabetyp der Methode undTpdurch den Rückgabetyp des Delegatentyps, und starten Sie den Prozess ohne Einschränkung neu.TpAndernfalls muss es sich um einen konstruierten Typ sein. GegebenTG, der generische Typ vonTp,Wenn
TaistTG, erbt vonTG, oder implementiert den TypTGgenau einmal, dann ersetzen Sie für jedes übereinstimmende TypargumentTaxvonTaundTpxvonTp, ersetzenTasie durchTaxundTpdurchTpxund starten Sie den Prozess mit einer generischen Argumenteinschränkung neu.Andernfalls schlägt die Typreferenz für die generische Methode fehl.
Der Erfolg des Typinschlusses garantiert nicht selbst, dass die Methode anwendbar ist.
Visual Basic language spec