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.
Een expressie is een reeks operatoren en operanden waarmee een berekening van een waarde wordt opgegeven of waarmee een variabele of constante wordt aangewezen. In dit hoofdstuk worden de syntaxis, volgorde van evaluatie van operanden en operatoren en de betekenis van expressies gedefinieerd.
Expression
: SimpleExpression
| TypeExpression
| MemberAccessExpression
| DictionaryAccessExpression
| InvocationExpression
| IndexExpression
| NewExpression
| CastExpression
| OperatorExpression
| ConditionalExpression
| LambdaExpression
| QueryExpression
| XMLLiteralExpression
| XMLMemberAccessExpression
;
Expressieclassificaties
Elke expressie wordt geclassificeerd als een van de volgende:
Een waarde. Elke waarde heeft een gekoppeld type.
Een variabele. Elke variabele heeft een gekoppeld type, namelijk het gedeclareerde type van de variabele.
Een naamruimte. Een expressie met deze classificatie kan alleen worden weergegeven als de linkerkant van een lidtoegang. In een andere context veroorzaakt een expressie die is geclassificeerd als een naamruimte een compileertijdfout.
Een type. Een expressie met deze classificatie kan alleen worden weergegeven als de linkerkant van een lidtoegang. In een andere context veroorzaakt een expressie die is geclassificeerd als een type een compileertijdfout.
Een methodegroep, een set methoden die overbelast zijn op dezelfde naam. Een methodegroep kan een gekoppelde doelexpressie en een lijst met gekoppelde typeargumenten hebben.
Een methodepointer, die de locatie van een methode vertegenwoordigt. Een methodeaanwijzer kan een gekoppelde doelexpressie en een lijst met gekoppelde typeargumenten hebben.
Een lambda-methode, een anonieme methode.
Een eigenschapsgroep, een set eigenschappen die overbelast zijn op dezelfde naam. Een eigenschapsgroep kan een gekoppelde doelexpressie hebben.
Toegang tot een eigendom. Elke eigenschapstoegang heeft een bijbehorend type, namelijk het type van de eigenschap. Een eigenschapstoegang kan een gekoppelde doelexpressie hebben.
Een late toegang, die een methode of eigenschapstoegang vertegenwoordigt die is uitgesteld tot de runtime. Een late toegang kan een gekoppelde doelexpressie en een lijst met gekoppelde typeargumenten hebben. Het type van een late toegang is altijd
Object.Toegang tot een evenement Elke gebeurtenistoegang heeft een gekoppeld type, namelijk het type gebeurtenis. Een gebeurtenistoegang kan een gekoppelde doelexpressie hebben. Een gebeurtenistoegang kan worden weergegeven als het eerste argument van de
RaiseEvent,AddHandlerenRemoveHandlerinstructies. In een andere context veroorzaakt een expressie die is geclassificeerd als gebeurtenistoegang een compilatiefout.Een letterlijke matrix, die de initiële waarden van een matrix aangeeft waarvan het type nog niet is bepaald.
Leegte. Dit gebeurt wanneer de expressie een aanroep van een subroutine is of een wachtoperatorexpressie zonder resultaat. Een expressie die als ongeldig is geclassificeerd, is alleen geldig in de context van een aanroepinstructie of een await-instructie.
Een standaardwaarde. Alleen de letterlijke gegevens
Nothingproduceren deze classificatie.
Het uiteindelijke resultaat van een expressie is meestal een waarde of een variabele, waarbij de andere categorieën expressies functioneren als tussenliggende waarden die alleen zijn toegestaan in bepaalde contexten.
Houd er rekening mee dat expressies waarvan het type een typeparameter is, kunnen worden gebruikt in instructies en expressies waarvoor het type expressie bepaalde kenmerken moet hebben (zoals een verwijzingstype, waardetype, afgeleid van een bepaald type, enzovoort) als de beperkingen voor de typeparameter voldoen aan deze kenmerken.
Expressie opnieuw classificeren
Normaal gesproken treedt er een compilatiefout op wanneer een expressie wordt gebruikt in een context waarvoor een andere classificatie is vereist dan die van de expressie, bijvoorbeeld een poging om een waarde toe te wijzen aan een letterlijke waarde. In veel gevallen is het echter mogelijk om de classificatie van een expressie te wijzigen via het herclassificatieproces.
Als herclassificatie slaagt, wordt de herclassificatie beoordeeld als verbreking of vermaling. Tenzij anders vermeld, worden alle herclassificaties in deze lijst breder.
De volgende typen expressies kunnen opnieuw worden geclassificeerd:
Een variabele kan opnieuw worden geclassificeerd als een waarde. De waarde die in de variabele is opgeslagen, wordt opgehaald.
Een methodegroep kan opnieuw worden geclassificeerd als een waarde. De expressie van de methodegroep wordt geïnterpreteerd als een aanroepexpressie met de bijbehorende doelexpressie en typeparameterlijst, en lege haakjes (dat wil gezegd,
fwordt geïnterpreteerd alsf()enf(Of Integer)wordt geïnterpreteerd alsf(Of Integer)()). Deze herclassificatie kan ertoe leiden dat de expressie opnieuw wordt geclassificeerd als ongeldig.Een methodepointer kan opnieuw worden geclassificeerd als een waarde. Deze herclassificatie kan alleen optreden in de context van een conversie waarin het doeltype bekend is. De expressie voor methodepointer wordt geïnterpreteerd als het argument voor een gemachtigde instantiëringsexpressie van het juiste type met de lijst met gekoppelde typeargumenten. Voorbeeld:
Delegate Sub D(i As Integer) Module Test Sub F(i As Integer) End Sub Sub Main() Dim del As D ' The next two lines are equivalent. del = AddressOf F del = New D(AddressOf F) End Sub End ModuleEen lambda-methode kan opnieuw worden geclassificeerd als een waarde. Als de herclassificatie plaatsvindt in de context van een conversie waarvan het doeltype bekend is, kunnen er twee herclassificaties plaatsvinden:
Als het doeltype een gemachtigdentype is, wordt de lambda-methode geïnterpreteerd als het argument voor een expressie voor gedelegeerde constructie van het juiste type.
Als het doeltype en
System.Linq.Expressions.Expression(Of T)Teen gemachtigde is, wordt de lambda-methode geïnterpreteerd alsof deze wordt gebruikt in expressies voor gedelegeerdenTen vervolgens geconverteerd naar een expressiestructuur.
Een lambda-methode asynchroon of iterator kan alleen worden geïnterpreteerd als het argument voor een expressie voor gedelegeerde constructie, als de gemachtigde geen ByRef-parameters heeft.
Als de conversie van een van de parametertypen van de gemachtigde naar de bijbehorende lambda-parametertypen een smalle conversie is, wordt de herclassificatie beoordeeld als smal; anders wordt het breder.
Opmerking. De exacte vertaling tussen lambda-methoden en expressiestructuren is mogelijk niet opgelost tussen versies van de compiler en valt buiten het bereik van deze specificatie. Voor Microsoft Visual Basic 11.0 kunnen alle lambda-expressies worden geconverteerd naar expressiestructuren waarvoor de volgende beperkingen gelden: (1) 1. Alleen lambda-expressies met één regel zonder ByRef-parameters kunnen worden geconverteerd naar expressiestructuren. Van de lambdas met één regel
Subkunnen alleen aanroepinstructies worden geconverteerd naar expressiestructuren. (2) Anonieme typeexpressies kunnen niet worden geconverteerd naar expressiestructuren als een eerdere initialisatiefunctie voor velden wordt gebruikt om een volgende veld-initialisatiefunctie te initialiseren, bijvoorbeeldNew With {.a=1, .b=.a}. (3) Object initialisatie-expressies kunnen niet worden geconverteerd naar expressiestructuren als een lid van het huidige object dat wordt geïnitialiseerd, wordt gebruikt in een van de veld initialisatiefuncties, bijvoorbeeldNew C1 With {.a=1, .b=.Method1()}. (4) Multidimensionale expressies voor het maken van matrices kunnen alleen worden geconverteerd naar expressiestructuren als ze hun elementtype expliciet declareren. (5) Expressies met late binding kunnen niet worden geconverteerd naar expressiestructuren. (6) Wanneer een variabele of veld wordt doorgegeven aan een aanroepexpressie, maar niet precies hetzelfde type heeft als de parameter ByRef, of wanneer een eigenschap wordt doorgegeven door ByRef, zijn normale VB-semantiek dat een kopie van het argument wordt doorgegeven door ByRef en de uiteindelijke waarde vervolgens wordt gekopieerd naar de variabele of eigenschap of eigenschap. In expressiestructuren gebeurt de copy-back niet. (7) Al deze beperkingen gelden ook voor geneste lambda-expressies.Als het doeltype niet bekend is, wordt de lambda-methode geïnterpreteerd als het argument voor een instantie-expressie van een gemachtigde van een anoniem gemachtigdetype met dezelfde handtekening van de lambda-methode. Als strikte semantiek wordt gebruikt en het type van een van de parameters wordt weggelaten, treedt er een compilatiefout op; anders wordt
Objectvervangen door een ontbrekend parametertype. Voorbeeld:Module Test Sub Main() ' Type of x will be equivalent to Func(Of Object, Object, Object) Dim x = Function(a, b) a + b ' Type of y will be equivalent to Action(Of Object, Object) Dim y = Sub(a, b) Console.WriteLine(a + b) End Sub End ModuleEen eigenschapsgroep kan opnieuw worden geclassificeerd als een eigenschapstoegang. De expressie van de eigenschapsgroep wordt geïnterpreteerd als een indexexpressie met lege haakjes (dat wil gezegd,
fwordt geïnterpreteerd alsf()).Een eigenschapstoegang kan opnieuw worden geclassificeerd als een waarde. De eigenschapstoegangsexpressie wordt geïnterpreteerd als een aanroepexpressie van de
Gettoegangsfunctie van de eigenschap. Als de eigenschap geen getter heeft, treedt er een compilatietijdfout op.Een late-gebonden toegang kan opnieuw worden geclassificeerd als een late-gebonden methode of toegang tot late afhankelijke eigenschappen. In een situatie waarin een late toegang opnieuw kan worden geclassificeerd, zowel als methodetoegang als als eigenschapstoegang, is herclassificatie van een eigenschapstoegang de voorkeur.
Een late toegang kan opnieuw worden geclassificeerd als een waarde.
Een letterlijke matrix kan opnieuw worden geclassificeerd als een waarde. Het type van de waarde wordt als volgt bepaald:
Als de herclassificatie plaatsvindt in de context van een conversie waarbij het doeltype bekend is en het doeltype een matrixtype is, wordt de letterlijke waarde van de matrix opnieuw geclassificeerd als een waarde van het type T(). Als het doeltype één niveau van nesten heeft
System.Collections.Generic.IList(Of T),IReadOnlyList(Of T)wordtIEnumerable(Of T)ICollection(Of T)IReadOnlyCollection(Of T)de letterlijke waarde van de matrix opnieuw geclassificeerd als een waarde van het type.T()Anders wordt de letterlijke matrix opnieuw geclassificeerd op een waarde waarvan het type een matrix van rang is die gelijk is aan het nestniveau, waarbij het elementtype wordt bepaald door het dominante type van de elementen in de initialisatiefunctie; als er geen dominant type kan worden bepaald,
Objectwordt gebruikt. Voorbeeld:' x Is GetType(Double(,,)) Dim x = { { { 1, 2.0 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } }.GetType() ' y Is GetType(Integer()) Dim y = { 1, 2, 3 }.GetType() ' z Is GetType(Object()) Dim z = { 1, "2" }.GetType() ' Error: Inconsistent nesting Dim a = { { 10 }, { 20, 30 } }.GetType()
Opmerking. Er is een kleine wijziging in het gedrag tussen versie 9.0 en versie 10.0 van de taal. Vóór 10.0 hebben initialisaties van matrixelementen geen invloed op deductie van het lokale variabeletype en nu wel. Dit zou dus
Dim a() = { 1, 2, 3 }zijn afgeleidObject()als het type inaversie 9.0 van de taal enInteger()in versie 10.0.De herclassificatie herinterpreteert vervolgens de letterlijke waarde van de matrix als een expressie voor het maken van een matrix. Dus de voorbeelden:
Dim x As Double = { 1, 2, 3, 4 } Dim y = { "a", "b" }zijn gelijk aan:
Dim x As Double = New Double() { 1, 2, 3, 4 } Dim y = New String() { "a", "b" }De herclassificatie wordt beoordeeld als smal als een conversie van een elementexpressie naar het type matrixelement wordt beperkt; anders wordt het beoordeeld als widening.
De standaardwaarde
Nothingkan opnieuw worden geclassificeerd als een waarde. In een context waarin het doeltype bekend is, is het resultaat de standaardwaarde van het doeltype. In een context waarin het doeltype niet bekend is, is het resultaat een null-waarde van het typeObject.
Een naamruimteexpressie, typeexpressie, gebeurtenistoegangsexpressie of ongeldige expressie kan niet opnieuw worden geclassificeerd. Meerdere herclassificaties kunnen tegelijkertijd worden uitgevoerd. Voorbeeld:
Module Test
Sub F(i As Integer)
End Sub
ReadOnly Property P() As Integer
Get
End Get
End Sub
Sub Main()
F(P)
End Property
End Module
In dit geval wordt de expressie P van de eigenschapsgroep eerst opnieuw geclassificeerd van een eigenschapsgroep naar een eigenschapstoegang en vervolgens opnieuw geclassificeerd vanuit een eigenschapstoegang tot een waarde. Het minste aantal herclassificaties wordt uitgevoerd om een geldige classificatie in de context te bereiken.
Constante expressies
Een constante expressie is een expressie waarvan de waarde tijdens het compileren volledig kan worden geëvalueerd.
ConstantExpression
: Expression
;
Het type van een constante expressie kan zijnByte: , SByte, ShortUShort, , UInteger, ULongSingleDoubleDecimalCharIntegerLongDate, Boolean, String, , Objectof elk opsommingstype. De volgende constructies zijn toegestaan in constante expressies:
Letterlijke gegevens (inclusief
Nothing).Verwijzingen naar constant typeleden of constante lokale bevolking.
Verwijzingen naar leden van opsommingstypen.
Subexpressies tussen haakjes.
Expressies voor dwang, mits het doeltype een van de bovenstaande typen is. Dwangbewerkingen van en
Stringnaar deze regel zijn een uitzondering op deze regel en zijn alleen toegestaan voor null-waarden, omdatStringconversies altijd worden uitgevoerd in de huidige cultuur van de uitvoeringsomgeving tijdens runtime. Houd er rekening mee dat constante dwangexpressies alleen intrinsieke conversies kunnen gebruiken.De
+operatoren en-Notunaire operatoren, mits de operand en het resultaat van een hierboven vermelde type zijn.De
+operators ,*\^And&Mod/-<<>>, ,OrXor><<>OrElse=AndAlso, en<==>binaire operatoren, mits elke operand en het resultaat van een hierboven vermelde type is.De voorwaardelijke operator If, opgegeven elke operand en het resultaat is van een type dat hierboven wordt vermeld.
De volgende runtimefuncties:
Microsoft.VisualBasic.Strings.ChrW;Microsoft.VisualBasic.Strings.Chrals de constante waarde tussen 0 en 128 ligt;Microsoft.VisualBasic.Strings.AscWals de constante tekenreeks niet leeg is;Microsoft.VisualBasic.Strings.Ascals de constante tekenreeks niet leeg is.
De volgende constructies zijn niet toegestaan in constante expressies:
- Impliciete binding via een
Withcontext.
Constante expressies van een integraal type (ULong, Long, UInteger, Integer, UShort, Shortof SByteByte) kunnen impliciet worden geconverteerd naar een smaller integraal type en constante expressies van het type Double kunnen impliciet worden geconverteerd naar Single, mits de waarde van de constante expressie binnen het bereik van het doeltype valt. Deze vermalingsconversies zijn toegestaan, ongeacht of er permissieve of strikte semantiek wordt gebruikt.
Late-Bound expressies
Wanneer het doel van een lidtoegangsexpressie of indexexpressie van het type Objectis, kan de verwerking van de expressie worden uitgesteld tot de uitvoeringstijd. Het uitstellen van de verwerking op deze manier wordt late binding genoemd. Met late binding kunnen Object variabelen op een typeloze manier worden gebruikt, waarbij alle resolutie van leden is gebaseerd op het werkelijke uitvoeringstype van de waarde in de variabele. Als strikte semantiek wordt opgegeven door de compilatieomgeving of door Option Strict, veroorzaakt late binding een compilatietijdfout. Niet-openbare leden worden genegeerd bij late binding, ook voor overbelastingsresolutie. Houd er rekening mee dat, in tegenstelling tot het vroege geval, het aanroepen of openen van een Shared lid laat gebonden ertoe leidt dat het aanroepdoel tijdens runtime wordt geëvalueerd. Als de expressie een aanroepexpressie is voor een lid dat is gedefinieerd op System.Object, vindt late binding niet plaats.
Over het algemeen worden late toegangsrechten tijdens runtime opgelost door de id op te zoeken op het werkelijke uitvoeringstype van de expressie. Als het opzoeken van leden met een late gebonden uitvoering mislukt, wordt er een System.MissingMemberException uitzondering gegenereerd. Omdat het opzoekprogramma voor leden met late grenzen uitsluitend wordt uitgevoerd op het runtimetype van de gekoppelde doelexpressie, is het runtimetype van een object nooit een interface. Daarom is het onmogelijk om toegang te krijgen tot interfaceleden in een laat gebonden toegangsexpressie voor leden.
De argumenten voor een laat gebonden lidtoegang worden geëvalueerd in de volgorde waarin ze worden weergegeven in de toegangsexpressie van leden: niet de volgorde waarin parameters worden gedeclareerd in het te late gebonden lid. In het volgende voorbeeld ziet u dit verschil:
Class C
Public Sub f(ByVal x As Integer, ByVal y As Integer)
End Sub
End Class
Module Module1
Sub Main()
Console.Write("Early-bound: ")
Dim c As C = New C
c.f(y:=t("y"), x:=t("x"))
Console.Write(vbCrLf & "Late-bound: ")
Dim o As Object = New C
o.f(y:=t("y"), x:=t("x"))
End Sub
Function t(ByVal s As String) As Integer
Console.Write(s)
Return 0
End Function
End Module
Met deze code wordt het volgende weergegeven:
Early-bound: xy
Late-bound: yx
Omdat er een late overbelastingsresolutie wordt uitgevoerd op het uitvoeringstijdtype van de argumenten, kan een expressie verschillende resultaten opleveren op basis van of deze wordt geëvalueerd tijdens het compileren of de uitvoeringstijd. In het volgende voorbeeld ziet u dit verschil:
Class Base
End Class
Class Derived
Inherits Base
End Class
Module Test
Sub F(b As Base)
Console.WriteLine("F(Base)")
End Sub
Sub F(d As Derived)
Console.WriteLine("F(Derived)")
End Sub
Sub Main()
Dim b As Base = New Derived()
Dim o As Object = b
F(b)
F(o)
End Sub
End Module
Met deze code wordt het volgende weergegeven:
F(Base)
F(Derived)
Eenvoudige expressies
Eenvoudige expressies zijn letterlijke, haakjes, exemplaarexpressies of eenvoudige naamexpressies.
SimpleExpression
: LiteralExpression
| ParenthesizedExpression
| InstanceExpression
| SimpleNameExpression
| AddressOfExpression
;
Letterlijke expressies
Letterlijke expressies evalueren de waarde die wordt vertegenwoordigd door de letterlijke waarde. Een letterlijke expressie wordt geclassificeerd als een waarde, met uitzondering van de letterlijke Nothingwaarde, die wordt geclassificeerd als een standaardwaarde.
LiteralExpression
: Literal
;
Haakjes tussen expressies
Een haakje-expressie bestaat uit een expressie tussen haakjes. Een haakje-expressie wordt geclassificeerd als een waarde en de ingesloten expressie moet worden geclassificeerd als een waarde. Een haakje expressie evalueert naar de waarde van de expressie tussen haakjes.
ParenthesizedExpression
: OpenParenthesis Expression CloseParenthesis
;
Exemplaarexpressies
Een exemplaarexpressie is het trefwoord Me. Het mag alleen worden gebruikt in de hoofdtekst van een niet-gedeelde methode, constructor of eigenschapstoegangsor. Deze wordt geclassificeerd als een waarde. Het trefwoord Me vertegenwoordigt het exemplaar van het type dat de methode of eigenschapstoegangsobject bevat die wordt uitgevoerd. Als een constructor expliciet een andere constructor ( sectieconstructors) aanroept, Me kan deze pas worden gebruikt nadat deze constructoraanroep is uitgevoerd, omdat het exemplaar nog niet is samengesteld.
InstanceExpression
: 'Me'
;
Eenvoudige naamexpressies
Een eenvoudige naamexpressie bestaat uit één id, gevolgd door een optionele lijst met typeargumenten.
SimpleNameExpression
: Identifier ( OpenParenthesis 'Of' TypeArgumentList CloseParenthesis )?
;
De naam wordt omgezet en geclassificeerd door de volgende 'eenvoudige regels voor naamomzetting':
Als de id overeenkomt met de naam van een lokale variabele, statische variabele, constante lokale parameter, parameter of parameter, verwijst de id naar de overeenkomende entiteit.
Als de id overeenkomt met een lokale variabele, statische variabele of constante lokale en een lijst met typeargumenten is opgegeven, treedt er een compilatietijdfout op. Als de id overeenkomt met een parameter voor het methodetype en er een lijst met typeargumenten is opgegeven, vindt er geen overeenkomst plaats en wordt de oplossing voortgezet. Als de id overeenkomt met een lokale variabele, is de lokale variabele die overeenkomt met de impliciete functie of
Getaccessor de lokale variabele retourneert en de expressie deel uitmaakt van een aanroepexpressie, aanroepinstructie of eenAddressOfexpressie, vindt er geen overeenkomst plaats en wordt de oplossing voortgezet.De expressie wordt geclassificeerd als een variabele als het een lokale variabele, statische variabele of parameter is. De expressie wordt geclassificeerd als een type als het een parameter voor het methodetype is. De expressie wordt geclassificeerd als een waarde als deze een constante lokale waarde is.
Voor elk genest type dat de expressie bevat, beginnend bij de binnenste en naar buitenste, als een zoekactie van de id in het type een overeenkomst oplevert met een toegankelijk lid:
- Als het lid van het overeenkomende type een typeparameter is, wordt het resultaat geclassificeerd als een type en is het de parameter van het overeenkomende type. Als er een lijst met typeargumenten is opgegeven, vindt er geen overeenkomst plaats en wordt de oplossing voortgezet.
- Als het type anders het onmiddellijk ingesloten type is en de zoekactie een lid van een niet-gedeeld type identificeert, is het resultaat hetzelfde als een lidtoegang tot het formulier
Me.E(Of A), waarEde id is enAde lijst met typeargumenten is, indien van toepassing. - Anders is het resultaat precies hetzelfde als een lidtoegang van het formulier
T.E(Of A), waarThet type is dat het overeenkomende lid bevat,Ede id is enAde lijst met typeargumenten, indien van toepassing. In dit geval is het een fout voor de id om te verwijzen naar een niet-gedeeld lid.
Ga voor elke geneste naamruimte vanaf de binnenste en naar de buitenste naamruimte als volgt te werk:
- Als de naamruimte een toegankelijk type met de opgegeven naam bevat en hetzelfde aantal typeparameters heeft als is opgegeven in de lijst met typeargumenten, indien van toepassing, verwijst de id naar dat type en wordt geclassificeerd als een type.
- Als er anders geen type argumentlijst is opgegeven en de naamruimte een naamruimtelid met de opgegeven naam bevat, verwijst de id naar die naamruimte en wordt geclassificeerd als een naamruimte.
- Als de naamruimte een of meer toegankelijke standaardmodules bevat en een lidnaamzoekactie van de id een toegankelijke overeenkomst produceert in precies één standaardmodule, is het resultaat precies hetzelfde als een lidtoegang tot het formulier
M.E(Of A), waarbijMde standaardmodule die het overeenkomende lid bevat,Ede id is enAde lijst met het typeargument is. indien aanwezig. Als de id overeenkomt met leden van het toegankelijke type in meer dan één standaardmodule, treedt er een compilatietijdfout op.
Als het bronbestand een of meer importaliassen heeft en de id overeenkomt met de naam van een van deze aliassen, verwijst de id naar die naamruimte of het type. Als er een lijst met typeargumenten wordt opgegeven, treedt er een compilatietijdfout op.
Als het bronbestand met de naamreferentie een of meer importbewerkingen bevat:
- Als de id overeenkomt met exact één type, importeert u de naam van een toegankelijk type met hetzelfde aantal parameters als is opgegeven in de lijst met typeargumenten, indien van toepassing, of een typelid, dan verwijst de id naar dat type of typelid. Als de id in meer dan één type overeenkomt met de naam van een toegankelijk type met hetzelfde aantal parameters als is opgegeven in de lijst met typeargumenten, indien van toepassing, of een toegankelijk typelid, treedt er een compilatiefout op.
- Als er anders geen lijst met typeargumenten is opgegeven en de id overeenkomt met exact één naamruimte met toegankelijke typen, verwijst de id naar die naamruimte. Als er geen lijst met typeargumenten is opgegeven en de id overeenkomt met meer dan één import van de naam van een naamruimte met toegankelijke typen, treedt er een compilatietijdfout op.
- Als de import een of meer toegankelijke standaardmodules bevat en een lidnaamzoekactie van de id een toegankelijke overeenkomst produceert in precies één standaardmodule, is het resultaat precies hetzelfde als een lidtoegang tot het formulier
M.E(Of A), waarbijMde standaardmodule die het overeenkomende lid bevat,Ede id is enAde lijst met het typeargument is, indien aanwezig. Als de id overeenkomt met leden van het toegankelijke type in meer dan één standaardmodule, treedt er een compilatietijdfout op.
Als in de compilatieomgeving een of meer importaliassen worden gedefinieerd en de id overeenkomt met de naam van een van deze aliassen, verwijst de id naar die naamruimte of het type. Als er een lijst met typeargumenten wordt opgegeven, treedt er een compilatietijdfout op.
Als in de compilatieomgeving een of meer importbewerkingen worden gedefinieerd:
- Als de id overeenkomt met exact één type, importeert u de naam van een toegankelijk type met hetzelfde aantal parameters als is opgegeven in de lijst met typeargumenten, indien van toepassing, of een typelid, dan verwijst de id naar dat type of typelid. Als de id in meer dan één type overeenkomt met de naam van een toegankelijk type met hetzelfde aantal typeparameters als is opgegeven in de lijst met typeargumenten, indien van toepassing, of een typelid, treedt er een compilatietijdfout op.
- Als er anders geen lijst met typeargumenten is opgegeven en de id overeenkomt met exact één naamruimte met toegankelijke typen, verwijst de id naar die naamruimte. Als er geen lijst met typeargumenten is opgegeven en de id overeenkomt met meer dan één import van de naam van een naamruimte met toegankelijke typen, treedt er een compilatietijdfout op.
- Als de import een of meer toegankelijke standaardmodules bevat en een lidnaamzoekactie van de id een toegankelijke overeenkomst produceert in precies één standaardmodule, is het resultaat precies hetzelfde als een lidtoegang tot het formulier
M.E(Of A), waarbijMde standaardmodule die het overeenkomende lid bevat,Ede id is enAde lijst met het typeargument is, indien aanwezig. Als de id overeenkomt met leden van het toegankelijke type in meer dan één standaardmodule, treedt er een compilatietijdfout op.
Anders is de naam die door de id wordt opgegeven, niet gedefinieerd.
Een eenvoudige naamexpressie die niet is gedefinieerd, is een compilatiefout.
Normaal gesproken kan een naam slechts eenmaal voorkomen in een bepaalde naamruimte. Omdat naamruimten echter kunnen worden gedeclareerd voor meerdere .NET-assembly's, is het mogelijk om een situatie te hebben waarin twee assembly's een type definiëren met dezelfde volledig gekwalificeerde naam. In dat geval heeft een type dat is gedeclareerd in de huidige set bronbestanden de voorkeur boven een type dat is gedeclareerd in een externe .NET-assembly. Anders is de naam dubbelzinnig en is er geen manier om de naam ondubbelzinnig te maken.
AddressOf-expressies
Een AddressOf expressie wordt gebruikt om een methodeaanwijzer te produceren. De expressie bestaat uit het AddressOf trefwoord en een expressie die moet worden geclassificeerd als een methodegroep of een late toegang. De methodegroep kan niet verwijzen naar constructors.
Het resultaat wordt geclassificeerd als een methodepointer, met dezelfde gekoppelde doelexpressie en type argumentlijst (indien aanwezig) als de methodegroep.
AddressOfExpression
: 'AddressOf' Expression
;
Type-expressies
Een typeexpressie is een GetType expressie, een TypeOf...Is expressie, een Is expressie of een GetXmlNamespace expressie.
TypeExpression
: GetTypeExpression
| TypeOfIsExpression
| IsExpression
| GetXmlNamespaceExpression
;
GetType-expressies
Een GetType expressie bestaat uit het trefwoord GetType en de naam van een type.
GetTypeExpression
: 'GetType' OpenParenthesis GetTypeTypeName CloseParenthesis
;
GetTypeTypeName
: TypeName
| QualifiedOpenTypeName
;
QualifiedOpenTypeName
: Identifier TypeArityList? (Period IdentifierOrKeyword TypeArityList?)*
| 'Global' Period IdentifierOrKeyword TypeArityList?
(Period IdentifierOrKeyword TypeArityList?)*
;
TypeArityList
: OpenParenthesis 'Of' CommaList? CloseParenthesis
;
CommaList
: Comma Comma*
;
Een GetType expressie wordt geclassificeerd als een waarde en de waarde is de weerspiegelingsklasse (System.Type) die de GetTypeTypeName vertegenwoordigt. Als De GetTypeTypeName een typeparameter is, retourneert de expressie het System.Type object dat overeenkomt met het typeargument dat is opgegeven voor de typeparameter tijdens runtime.
De GetTypeTypeName is op twee manieren speciaal:
Het is toegestaan,
System.Voidde enige plaats in de taal waarnaar naar deze typenaam kan worden verwezen.Het kan een geconstrueerd algemeen type zijn waarbij de typeargumenten worden weggelaten. Hierdoor kan de
GetTypeexpressie hetSystem.Typeobject retourneren dat overeenkomt met het algemene type zelf.
In het volgende voorbeeld ziet u de GetType expressie:
Module Test
Sub Main()
Dim t As Type() = { GetType(Integer), GetType(System.Int32), _
GetType(String), GetType(Double()) }
Dim i As Integer
For i = 0 To t.Length - 1
Console.WriteLine(t(i).Name)
Next i
End Sub
End Module
De resulterende uitvoer is:
Int32
Int32
String
Double[]
TypeOf... Is-expressies
Er wordt een TypeOf...Is expressie gebruikt om te controleren of het runtimetype van een waarde compatibel is met een bepaald type. De eerste operand moet worden geclassificeerd als een waarde, kan geen opnieuw geclassificeerde lambdamethode zijn en moet van een verwijzingstype of een niet-getraind typeparametertype zijn. De tweede operand moet een typenaam zijn. Het resultaat van de expressie wordt geclassificeerd als een waarde en is een Boolean waarde. De expressie evalueert of True het runtimetype van de operand een identiteit, standaard, verwijzing, matrix, waardetype of type parameterconversie heeft naar het type, False anders. Er treedt een compilatiefout op als er geen conversie bestaat tussen het type expressie en het specifieke type.
TypeOfIsExpression
: 'TypeOf' Expression 'Is' LineTerminator? TypeName
;
Is-expressies
Een Is of IsNot expressie wordt gebruikt om een verwijzingsvergelijking van gelijkheid uit te voeren.
IsExpression
: Expression 'Is' LineTerminator? Expression
| Expression 'IsNot' LineTerminator? Expression
;
Elke expressie moet worden geclassificeerd als een waarde en het type van elke expressie moet een verwijzingstype, een niet-gekoppeld typeparametertype of een null-waardetype zijn. Als het type van een expressie een niet-gekoppeld typeparametertype of null-waardetype is, moet de andere expressie echter de letterlijke Nothingwaarde zijn.
Het resultaat wordt geclassificeerd als een waarde en wordt getypt als Boolean. Een Is bewerking evalueert of True beide waarden verwijzen naar hetzelfde exemplaar of beide waarden, Nothingof False anderszins. Een IsNot bewerking evalueert of False beide waarden verwijzen naar hetzelfde exemplaar of beide waarden, Nothingof True anderszins.
GetXmlNamespace-expressies
Een GetXmlNamespace expressie bestaat uit het trefwoord GetXmlNamespace en de naam van een XML-naamruimte die is gedeclareerd door het bronbestand of de compilatieomgeving.
GetXmlNamespaceExpression
: 'GetXmlNamespace' OpenParenthesis XMLNamespaceName? CloseParenthesis
;
Een GetXmlNamespace expressie wordt geclassificeerd als een waarde en de waarde is een exemplaar van System.Xml.Linq.XNamespace die de XMLNamespaceName vertegenwoordigt. Als dat type niet beschikbaar is, treedt er een compilatietijdfout op.
Voorbeeld:
Imports <xmlns:db="http://example.org/database">
Module Test
Sub Main()
Dim db = GetXmlNamespace(db)
' The following are equivalent
Dim customer1 = _
New System.Xml.Linq.XElement(db + "customer", "Bob")
Dim customer2 = <db:customer>Bob</>
End Sub
End Module
Alles tussen de haakjes wordt beschouwd als onderdeel van de naamruimtenaam, dus XML-regels rond zaken zoals witruimte worden toegepast. Voorbeeld:
Imports <xmlns:db-ns="http://example.org/database">
Module Test
Sub Main()
' Error, XML name expected
Dim db1 = GetXmlNamespace( db-ns )
' Error, ')' expected
Dim db2 = GetXmlNamespace(db _
)
' OK.
Dim db3 = GetXmlNamespace(db-ns)
End Sub
End Module
De XML-naamruimteexpressie kan ook worden weggelaten. In dat geval retourneert de expressie het object dat de standaard-XML-naamruimte vertegenwoordigt.
Expressies voor lidtoegang
Een expressie voor lidtoegang wordt gebruikt voor toegang tot een lid van een entiteit.
MemberAccessExpression
: MemberAccessBase? Period IdentifierOrKeyword
( OpenParenthesis 'Of' TypeArgumentList CloseParenthesis )?
;
MemberAccessBase
: Expression
| NonArrayTypeName
| 'Global'
| 'MyClass'
| 'MyBase'
;
Een lidtoegang tot het formulier E.I(Of A), waarbij E een expressie, een naam van een niet-matrixtype, het trefwoord Globalof weggelaten wordt en I een id is met een optionele lijst Amet argumenttypen, wordt als volgt geëvalueerd en geclassificeerd:
Als
Eu dit weglaat, wordt de expressie uit de direct bevattendeWithinstructie vervangenEdoor en wordt de lidtoegang uitgevoerd. Als er geen instructie is,Withtreedt er een compilatiefout op.Als
Edeze is geclassificeerd als een naamruimte ofEhet trefwoordGlobalis, wordt het opzoeken van leden uitgevoerd in de context van de opgegeven naamruimte. AlsIdit de naam is van een toegankelijk lid van die naamruimte met hetzelfde aantal typeparameters als is opgegeven in de lijst met typeargumenten, indien van toepassing, is het resultaat dat lid. Het resultaat wordt geclassificeerd als een naamruimte of een type, afhankelijk van het lid. Anders treedt er een compilatietijdfout op.Als
Edit een type of expressie is die als een type is geclassificeerd, wordt de opzoekactie van het lid uitgevoerd in de context van het opgegeven type. AlsIdit de naam is van een toegankelijk lid vanE, wordt dezeE.Ials volgt geëvalueerd en geclassificeerd:- Als
Ihet trefwoordNewis enEgeen opsomming is, treedt er een compileertijdfout op. - Als
Iu een type identificeert met hetzelfde aantal typeparameters als is opgegeven in de lijst met typeargumenten, indien van toepassing, is het resultaat dat type. - Als
Ieen of meer methoden worden geïdentificeerd, is het resultaat een methodegroep met de lijst met gekoppelde typeargumenten en geen gekoppelde doelexpressie. - Als
Ieen of meer eigenschappen worden geïdentificeerd en er geen lijst met typeargumenten is opgegeven, is het resultaat een eigenschapsgroep zonder gekoppelde doelexpressie. - Als
Ieen gedeelde variabele wordt geïdentificeerd en er geen lijst met typeargumenten is opgegeven, is het resultaat een variabele of een waarde. Als de variabele het kenmerk Alleen-lezen heeft en de verwijzing zich buiten de gedeelde constructor bevindt van het type waarin de variabele wordt gedeclareerd, is het resultaat de waarde van de gedeelde variabeleIinE. Anders is het resultaat de gedeelde variabeleIinE. - Als
Ieen gedeelde gebeurtenis wordt geïdentificeerd en er geen lijst met typeargumenten is opgegeven, is het resultaat een gebeurtenistoegang zonder gekoppelde doelexpressie. - Als
Ieen constante wordt geïdentificeerd en er geen lijst met typeargumenten is opgegeven, is het resultaat de waarde van die constante. - Als
Ieen opsommingslid wordt geïdentificeerd en er geen lijst met typeargumenten is opgegeven, is het resultaat de waarde van dat opsommingslid. - Anders is
E.Ieen ongeldige lidverwijzing en treedt er een compilatiefout op.
- Als
Als
Ewordt geclassificeerd als een variabele of waarde, waarvan het type isT, wordt de opzoekactie van het lid uitgevoerd in de context vanT. AlsIdit de naam is van een toegankelijk lid vanT, wordt dezeE.Ials volgt geëvalueerd en geclassificeerd:- Als
Ihet trefwoordNew,EisMe,MyBaseof ofMyClassen er geen typeargumenten zijn opgegeven, is het resultaat een methodegroep die de instantieconstructors vertegenwoordigt van het type vanEhet type met een gekoppelde doelexpressie vanEen geen type argumentlijst. Anders treedt er een compilatietijdfout op. - Als
Ieen of meer methoden worden geïdentificeerd, inclusief uitbreidingsmethoden alsTdat nietObjectzo is, is het resultaat een methodegroep met de lijst met gekoppelde typeargumenten en een bijbehorende doelexpressie vanE. - Als
Ieen of meer eigenschappen worden geïdentificeerd en er geen typeargumenten zijn opgegeven, is het resultaat een eigenschapsgroep met een bijbehorende doelexpressie vanE. - Als
Ieen gedeelde variabele of een exemplaarvariabele wordt geïdentificeerd en er geen typeargumenten zijn opgegeven, is het resultaat een variabele of een waarde. Als de variabele het kenmerk Alleen-lezen heeft en de verwijzing zich buiten een constructor bevindt van de klasse waarin de variabele geschikt is voor het type variabele (gedeeld of exemplaar), is het resultaat de waarde van de variabeleIin het object waarnaarEwordt verwezen. AlsTdit een verwijzingstype is, is het resultaat de variabeleIin het object waarnaar wordt verwezen.ETAls dit niet het waardetype is en de expressieEwordt geclassificeerd als een variabele, is het resultaat een variabele. Anders is het resultaat een waarde. - Als
Ieen gebeurtenis wordt geïdentificeerd en er geen typeargumenten zijn opgegeven, is het resultaat een gebeurtenistoegang met een bijbehorende doelexpressie vanE. - Als
Ieen constante wordt geïdentificeerd en er geen typeargumenten zijn opgegeven, is het resultaat de waarde van die constante. - Als
Ieen opsommingslid wordt geïdentificeerd en er geen typeargumenten zijn opgegeven, is het resultaat de waarde van dat opsommingslid. - Als
Tdat het isObject, is het resultaat een te laat gebonden lidzoekactie die is geclassificeerd als een late-gebonden toegang met de lijst met gekoppelde typeargumenten en een bijbehorende doelexpressie vanE.
- Als
Anders is
E.Ieen ongeldige lidverwijzing en treedt er een compilatiefout op.
Een lidtoegang van het formulier MyClass.I(Of A) is gelijk aan Me.I(Of A), maar alle leden die erop worden geopend, worden behandeld alsof de leden niet kunnen worden overschreven. Het lid dat wordt geopend, wordt dus niet beïnvloed door het runtimetype van de waarde waarop het lid wordt geopend.
Een lidtoegang van het formulier MyBase.I(Of A) is gelijk aan CType(Me, T).I(Of A) waar T het directe basistype is van het type dat de toegangsexpressie van het lid bevat. Alle methode-aanroepen worden behandeld alsof de methode die wordt aangeroepen, niet kan worden overschreven. Deze vorm van lidtoegang wordt ook wel een basistoegang genoemd.
In het volgende voorbeeld ziet u hoe Me, MyBase en MyClass relateren:
Class Base
Public Overridable Sub F()
Console.WriteLine("Base.F")
End Sub
End Class
Class Derived
Inherits Base
Public Overrides Sub F()
Console.WriteLine("Derived.F")
End Sub
Public Sub G()
MyClass.F()
End Sub
End Class
Class MoreDerived
Inherits Derived
Public Overrides Sub F()
Console.WriteLine("MoreDerived.F")
End Sub
Public Sub H()
MyBase.F()
End Sub
End Class
Module Test
Sub Main()
Dim x As MoreDerived = new MoreDerived()
x.F()
x.G()
x.H()
End Sub
End Module
Met deze code wordt het volgende afgedrukt:
MoreDerived.F
Derived.F
Derived.F
Wanneer een lidtoegangsexpressie begint met het trefwoord, vertegenwoordigt het trefwoord Globalde buitenste naamruimte met een naam, wat handig is in situaties waarin een declaratie een tussenliggende naamruimte schaduwt. Met Global het trefwoord kan 'ontsnappen' naar de buitenste naamruimte in die situatie. Voorbeeld:
Class System
End Class
Module Test
Sub Main()
' Error: Class System does not contain Console
System.Console.WriteLine("Hello, world!")
' Legal, binds to System in outermost namespace
Global.System.Console.WriteLine("Hello, world!")
End Sub
End Module
In het bovenstaande voorbeeld is de eerste methode-aanroep ongeldig omdat de id System is gebonden aan de klasse System, niet de naamruimte System. De enige manier om toegang te krijgen tot de System naamruimte is om Global te ontsnappen aan de buitenste naamruimte.
Als het lid dat wordt geopend, wordt gedeeld, is een expressie aan de linkerkant van de periode overbodig en wordt deze niet geëvalueerd, tenzij de lidtoegang te laat wordt uitgevoerd. Denk bijvoorbeeld aan de volgende code:
Class C
Public Shared F As Integer = 10
End Class
Module Test
Public Function ReturnC() As C
Console.WriteLine("Returning a new instance of C.")
Return New C()
End Function
Public Sub Main()
Console.WriteLine("The value of F is: " & ReturnC().F)
End Sub
End Module
Deze wordt afgedrukt The value of F is: 10 omdat de functie ReturnC niet hoeft te worden aangeroepen om een exemplaar C van toegang te bieden tot het gedeelde lid F.
Identieke type- en lidnamen
Het is niet ongebruikelijk dat leden dezelfde naam gebruiken als hun type. In dat geval kan echter onhandige naamverberging optreden:
Enum Color
Red
Green
Yellow
End Enum
Class Test
ReadOnly Property Color() As Color
Get
Return Color.Red
End Get
End Property
Shared Function DefaultColor() As Color
Return Color.Green ' Binds to the instance property!
End Function
End Class
In het vorige voorbeeld wordt de eenvoudige naam Color in DefaultColor bindt aan de exemplaareigenschap in plaats van het type. Omdat er niet naar een exemplaarlid kan worden verwezen in een gedeeld lid, is dit normaal gesproken een fout.
Een speciale regel biedt echter toegang tot het type in dit geval. Als de basisexpressie van een lidtoegangsexpressie een eenvoudige naam is en wordt gekoppeld aan een constante, veld, eigenschap, lokale variabele of parameter waarvan het type dezelfde naam heeft, kan de basisexpressie verwijzen naar het lid of het type. Dit kan nooit tot dubbelzinnigheid leiden omdat de leden die van beide kunnen worden geopend, hetzelfde zijn.
Standaardexemplaren
In sommige situaties hebben klassen die zijn afgeleid van een algemene basisklasse meestal of altijd slechts één exemplaar. De meeste vensters die in een gebruikersinterface worden weergegeven, hebben bijvoorbeeld maar één exemplaar dat op elk gewenst moment op het scherm wordt weergegeven. Om het werken met deze typen klassen te vereenvoudigen, kan Visual Basic automatisch standaardexemplaren genereren van de klassen die één eenvoudig exemplaar voor elke klasse bieden.
Standaardexemplaren worden altijd gemaakt voor een reeks typen in plaats van voor één bepaald type. In plaats van een standaardexemplaren te maken voor een klasse Form1 die is afgeleid van formulier, worden standaardexemplaren gemaakt voor alle klassen die zijn afgeleid van formulier. Dit betekent dat elke afzonderlijke klasse die is afgeleid van de basisklasse, niet speciaal hoeft te worden gemarkeerd om een standaardexemplaren te hebben.
Het standaardexemplaren van een klasse wordt vertegenwoordigd door een door compiler gegenereerde eigenschap die het standaardexemplaren van die klasse retourneert. De eigenschap die wordt gegenereerd als lid van een klasse, de groepsklasse genoemd, die standaardexemplaren beheert en vernietigt voor alle klassen die zijn afgeleid van de specifieke basisklasse. Alle standaardexemplaren van klassen die zijn Form afgeleid van, kunnen bijvoorbeeld worden verzameld in de MyForms klasse. Als een exemplaar van de groepsklasse wordt geretourneerd door de expressie My.Forms, krijgt de volgende code toegang tot de standaardexemplaren van afgeleide klassen Form1 en Form2:
Class Form1
Inherits Form
Public x As Integer
End Class
Class Form2
Inherits Form
Public y As Integer
End Class
Module Main
Sub Main()
My.Forms.Form1.x = 10
Console.WriteLine(My.Forms.Form2.y)
End Sub
End Module
Standaardexemplaren worden pas gemaakt als de eerste verwijzing naar deze exemplaren; Als u de eigenschap voor het standaardexemplaren ophaalt, wordt het standaardexemplaren gemaakt als deze nog niet is gemaakt of is ingesteld op Nothing. Als u wilt testen op het bestaan van een standaardexemplaren, wordt het standaardexemplaren niet gemaakt wanneer een standaardexemplaren het doel van een Is of IsNot operator zijn. Het is dus mogelijk om te testen of een standaardexemplaren of een andere verwijzing zijn Nothing zonder dat het standaardexemplaren worden gemaakt.
Standaardexemplaren zijn bedoeld om eenvoudig te verwijzen naar het standaardexemplaren van buiten de klasse met het standaardexemplaren. Het gebruik van een standaardexemplaren vanuit een klasse die definieert, kan verwarring veroorzaken over het exemplaar waarnaar wordt verwezen, d.w.w.v. het standaardexemplaren of het huidige exemplaar. Met de volgende code wordt bijvoorbeeld alleen de waarde x in het standaardexemplaren gewijzigd, ook al wordt deze aangeroepen vanuit een ander exemplaar. De code zou dus de waarde 5 afdrukken in plaats van 10:
Class Form1
Inherits Form
Public x As Integer = 5
Public Sub ChangeX()
Form1.x = 10
End Sub
End Class
Module Main
Sub Main()
Dim f As Form1 = New Form1()
f.ChangeX()
Console.WriteLine(f.x)
End Sub
End Module
Om dit soort verwarring te voorkomen, is het niet geldig om te verwijzen naar een standaardexemplaren vanuit een instantiemethode van het type van het standaardexemplaren.
Standaardexemplaren en typenamen
Een standaardexemplaren kunnen ook rechtstreeks toegankelijk zijn via de naam van het type. In dit geval wordt in een expressiecontext waarin de naam van het type de expressie Eniet is toegestaan, waarbij E de volledig gekwalificeerde naam van de klasse met een standaardexemplaren wordt aangegeven E'in , waarbij E' een expressie wordt aangegeven die de standaardexemplareneigenschap ophaalt. Als standaardexemplaren voor klassen die zijn afgeleid van Form het toestaan van toegang tot het standaardexemplaren via de typenaam, is de volgende code bijvoorbeeld gelijk aan de code in het vorige voorbeeld:
Module Main
Sub Main()
Form1.x = 10
Console.WriteLine(Form2.y)
End Sub
End Module
Dit betekent ook dat een standaardexemplaren die toegankelijk zijn via de naam van het type, ook kunnen worden toegewezen via de naam van het type. Met de volgende code wordt bijvoorbeeld het standaardexemplaren ingesteld Form1Nothingop:
Module Main
Sub Main()
Form1 = Nothing
End Sub
End Module
Houd er rekening mee dat de betekenis van E.I een E klasse vertegenwoordigt en I een gedeeld lid niet verandert. Een dergelijke expressie heeft nog steeds rechtstreeks toegang tot het gedeelde lid van het klasse-exemplaar en verwijst niet naar het standaardexemplaren.
Groepsklassen
Het Microsoft.VisualBasic.MyGroupCollectionAttribute kenmerk geeft de groepsklasse aan voor een familie van standaardexemplaren. Het kenmerk heeft vier parameters:
De parameter
TypeToCollectgeeft de basisklasse voor de groep op. Alle geïnstantieerbare klassen zonder open typeparameters die zijn afgeleid van een type met deze naam (ongeacht typeparameters) hebben automatisch een standaardexemplaren.De parameter
CreateInstanceMethodNamegeeft de methode op die moet worden aangeroepen in de groepsklasse om een nieuw exemplaar te maken in een standaardexemplareneigenschap.Met de parameter
DisposeInstanceMethodNamewordt de methode opgegeven die moet worden aangeroepen in de groepsklasse om een standaardexemplareneigenschap te verwijderen als aan de standaardexemplareneigenschap de waardeNothingwordt toegewezen.De parameter
DefaultInstanceAliasspecificeert de expressieE'die moet worden vervangen door de klassenaam als de standaardexemplaren rechtstreeks toegankelijk zijn via hun typenaam. Als deze parameter of een lege tekenreeks isNothing, zijn standaardexemplaren van dit groepstype niet rechtstreeks toegankelijk via de naam van het type. (Opmerking. In alle huidige implementaties van de Visual Basic-taal wordt deDefaultInstanceAliasparameter genegeerd, met uitzondering van de code die door de compiler is verstrekt.)
Meerdere typen kunnen in dezelfde groep worden verzameld door de namen van de typen en methoden in de eerste drie parameters te scheiden met komma's. Er moet hetzelfde aantal items in elke parameter zijn en de lijstelementen worden in volgorde vergeleken. Met de volgende kenmerkdeclaratie worden bijvoorbeeld typen verzameld die zijn afgeleid van C1of C3C2 in één groep:
<Microsoft.VisualBasic.MyGroupCollection("C1, C2, C3", _
"CreateC1, CreateC2, CreateC3", _
"DisposeC1, DisposeC2, DisposeC3", "My.Cs")>
Public NotInheritable Class MyCs
...
End Class
De handtekening van de create-methode moet van het formulier Shared Function <Name>(Of T As {New, <Type>})(Instance Of T) As Tzijn. De verwijderingsmethode moet van het formulier Shared Sub <Name>(Of T As <Type>)(ByRef Instance Of T)zijn. De groepsklasse voor het voorbeeld in de voorgaande sectie kan dus als volgt worden gedeclareerd:
<Microsoft.VisualBasic.MyGroupCollection("Form", "Create", _
"Dispose", "My.Forms")> _
Public NotInheritable Class MyForms
Private Shared Function Create(Of T As {New, Form}) _
(Instance As T) As T
If Instance Is Nothing Then
Return New T()
Else
Return Instance
End If
End Function
Private Shared Sub Dispose(Of T As Form)(ByRef Instance As T)
Instance.Close()
Instance = Nothing
End Sub
End Class
Als een bronbestand een afgeleide klasse Form1heeft gedeclareerd, is de gegenereerde groepsklasse gelijk aan:
<Microsoft.VisualBasic.MyGroupCollection("Form", "Create", _
"Dispose", "My.Forms")> _
Public NotInheritable Class MyForms
Private Shared Function Create(Of T As {New, Form}) _
(Instance As T) As T
If Instance Is Nothing Then
Return New T()
Else
Return Instance
End If
End Function
Private Shared Sub Dispose(Of T As Form)(ByRef Instance As T)
Instance.Close()
Instance = Nothing
End Sub
Private m_Form1 As Form1
Public Property Form1() As Form1
Get
Return Create(m_Form1)
End Get
Set (Value As Form1)
If Value IsNot Nothing AndAlso Value IsNot m_Form1 Then
Throw New ArgumentException( _
"Property can only be set to Nothing.")
End If
Dispose(m_Form1)
End Set
End Property
End Class
Verzameling extensiemethoden
Extensiemethoden voor de toegangsexpressie E.I voor leden worden verzameld door alle extensiemethoden te verzamelen met de naam I die beschikbaar is in de huidige context:
- Eerst wordt elk geneste type met de expressie gecontroleerd, te beginnen bij de binnenste en naar de buitenste.
- Vervolgens wordt elke geneste naamruimte gecontroleerd, te beginnen bij de binnenste en naar de buitenste naamruimte te gaan.
- Vervolgens worden de importbewerkingen in het bronbestand gecontroleerd.
- Vervolgens worden de importbewerkingen gecontroleerd die zijn gedefinieerd door de compilatieomgeving.
Er wordt alleen een extensiemethode verzameld als er een brede systeemeigen conversie van het doelexpressietype naar het type van de eerste parameter van de extensiemethode bestaat. En in tegenstelling tot gewone eenvoudige naamexpressiebinding verzamelt de zoekopdracht alle extensiemethoden; de verzameling stopt niet wanneer een extensiemethode wordt gevonden. 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 Double)
End Sub
End Module
End Namespace
Namespace N1.N2.N3
Module Test
Sub Main()
Dim x As New C1()
' Calls N1C1Extensions.M1
x.M1(10)
End Sub
End Module
End Namespace
In dit voorbeeld worden beide beschouwd als uitbreidingsmethoden, ook al N2C1Extensions.M1 worden ze eerder N1C1Extensions.M1gevonden. Zodra alle uitbreidingsmethoden zijn verzameld, worden ze vervolgens genezen. Currying gebruikt het doel van de aanroep van de extensiemethode en past deze toe op de aanroep van de extensiemethode, wat resulteert in een nieuwe methodehandtekening waarbij de eerste parameter is verwijderd (omdat deze is opgegeven). Voorbeeld:
Imports System.Runtime.CompilerServices
Module Ext1
<Extension> _
Sub M(x As Integer, y As Integer)
End Sub
End Module
Module Ext2
<Extension> _
Sub M(x As Integer, y As Double)
End Sub
End Module
Module Main
Sub Test()
Dim v As Integer = 10
' The curried method signatures considered are:
' Ext1.M(y As Integer)
' Ext2.M(y As Double)
v.M(10)
End Sub
End Module
In het bovenstaande voorbeeld is het curriede resultaat van het toepassen vExt1.M op de methodehandtekening Sub M(y As Integer).
Naast het verwijderen van de eerste parameter van de extensiemethode, worden ook alle parameters van het methodetype verwijderd die deel uitmaken van het type van de eerste parameter. Wanneer u een extensiemethode gebruikt met de parameter van het methodetype, wordt typedeductie toegepast op de eerste parameter en wordt het resultaat vastgesteld voor alle typeparameters die worden afgeleid. Als typedeductie mislukt, wordt de methode genegeerd. Voorbeeld:
Imports System.Runtime.CompilerServices
Module Ext1
<Extension> _
Sub M(Of T, U)(x As T, y As U)
End Sub
End Module
Module Ext2
<Extension> _
Sub M(Of T)(x As T, y As T)
End Sub
End Module
Module Main
Sub Test()
Dim v As Integer = 10
' The curried method signatures considered are:
' Ext1.M(Of U)(y As U)
' Ext2.M(y As Integer)
v.M(10)
End Sub
End Module
In het bovenstaande voorbeeld is het curriede resultaat van toepassing vExt1.M op de methodehandtekening Sub M(Of U)(y As U), omdat de typeparameter T wordt afgeleid als gevolg van de kerrie en nu is opgelost. Omdat de typeparameter U niet is afgeleid als onderdeel van de kerrie, blijft deze een open parameter. Op dezelfde manier, omdat de typeparameter T wordt afgeleid als gevolg van het toepassen Ext2.Mv op , wordt het type parameter y opgelost als Integer. Het wordt niet afgeleid dat het een ander type is. Wanneer u de handtekening gebruikt, worden alle beperkingen, met uitzondering van New beperkingen, ook toegepast. Als niet aan de beperkingen wordt voldaan of afhankelijk is van een type dat niet is afgeleid als onderdeel van curry's, wordt de extensiemethode genegeerd. Voorbeeld:
Imports System.Runtime.CompilerServices
Module Ext1
<Extension> _
Sub M1(Of T As Structure)(x As T, y As Integer)
End Sub
<Extension> _
Sub M2(Of T As U, U)(x As T, y As U)
End Sub
End Module
Module Main
Sub Test()
Dim s As String = "abc"
' Error: String does not satisfy the Structure constraint
s.M1(10)
' Error: T depends on U, which cannot be inferred
s.M2(10)
End Sub
End Module
Opmerking. Een van de belangrijkste redenen voor het uitvoeren van kerrie van extensiemethoden is dat queryexpressies het type iteratie kunnen afleiden voordat de argumenten worden geëvalueerd voor een querypatroonmethode. Aangezien de meeste querypatroonmethoden lambda-expressies gebruiken, waarvoor typedeductie zelf is vereist, vereenvoudigt dit het proces van het evalueren van een query-expressie aanzienlijk.
In tegenstelling tot normale interfaceovername zijn extensiemethoden die twee interfaces uitbreiden die niet met elkaar verband houden beschikbaar, zolang ze niet dezelfde curriede handtekening hebben:
Imports System.Runtime.CompilerServices
Interface I1
End Interface
Interface I2
End Interface
Class C1
Implements I1, I2
End Class
Module I1Ext
<Extension> _
Sub M1(i As I1, x As Integer)
End Sub
<Extension> _
Sub M2(i As I1, x As Integer)
End Sub
End Module
Module I2Ext
<Extension> _
Sub M1(i As I2, x As Integer)
End Sub
<Extension> _
Sub M2(I As I2, x As Double)
End Sub
End Module
Module Main
Sub Test()
Dim c As New C1()
' Error: M is ambiguous between I1Ext.M1 and I2Ext.M1.
c.M1(10)
' Calls I1Ext.M2
c.M2(10)
End Sub
End Module
Ten slotte is het belangrijk om te onthouden dat extensiemethoden niet worden overwogen bij het uitvoeren van late binding:
Module Test
Sub Main()
Dim o As Object = ...
' Ignores extension methods
o.M1()
End Sub
End Module
Toegangsexpressies voor woordenlijstlid
Een toegangsexpressie voor woordenlijstleden wordt gebruikt om een lid van een verzameling op te zoeken. Toegang tot woordenlijstleden heeft de vorm van E!I, waarbij E een expressie is die is geclassificeerd als een waarde en I een id is.
DictionaryAccessExpression
: Expression? '!' IdentifierOrKeyword
;
Het type expressie moet een standaardeigenschap hebben geïndexeerd met één String parameter. De toegangsexpressie E!I voor woordenlijstleden wordt omgezet in de expressie E.D("I"), waar D de standaardeigenschap van Eis. Voorbeeld:
Class Keys
Public ReadOnly Default Property Item(s As String) As Integer
Get
Return 10
End Get
End Property
End Class
Module Test
Sub Main()
Dim x As Keys = new Keys()
Dim y As Integer
' The two statements are equivalent.
y = x!abc
y = x("abc")
End Sub
End Module
Als een uitroepteken zonder expressie wordt opgegeven, wordt ervan uitgegaan dat de expressie uit de direct bevatde With instructie. Als er geen instructie is, With treedt er een compilatiefout op.
Aanroepexpressies
Een aanroepexpressie bestaat uit een aanroepdoel en een optionele lijst met argumenten.
InvocationExpression
: Expression ( OpenParenthesis ArgumentList? CloseParenthesis )?
;
ArgumentList
: PositionalArgumentList
| PositionalArgumentList Comma NamedArgumentList
| NamedArgumentList
;
PositionalArgumentList
: Expression? ( Comma Expression? )*
;
NamedArgumentList
: IdentifierOrKeyword ColonEquals Expression
( Comma IdentifierOrKeyword ColonEquals Expression )*
;
De doelexpressie moet worden geclassificeerd als een methodegroep of een waarde waarvan het type een gemachtigde is. Als de doelexpressie een waarde is waarvan het type een gemachtigde is, wordt het doel van de aanroepexpressie de methodegroep voor het Invoke lid van het gemachtigdetype en wordt de doelexpressie de bijbehorende doelexpressie van de methodegroep.
Een lijst met argumenten heeft twee secties: positionele argumenten en benoemde argumenten.
Positionele argumenten zijn expressies en moeten voorafgaan aan benoemde argumenten.
Benoemde argumenten beginnen met een id die overeenkomt met trefwoorden, gevolgd door := en een expressie.
Als de methodegroep slechts één toegankelijke methode bevat, waaronder zowel exemplaar- als extensiemethoden, en die methode geen argumenten heeft en een functie is, wordt de methodegroep geïnterpreteerd als een aanroepexpressie met een lege argumentenlijst en wordt het resultaat gebruikt als het doel van een aanroepexpressie met de opgegeven argumentenlijst(en). Voorbeeld:
Class C1
Function M1() As Integer()
Return New Integer() { 1, 2, 3 }
End Sub
End Class
Module Test
Sub Main()
Dim c As New C1()
' Prints 3
Console.WriteLine(c.M1(2))
End Sub
End Module
Anders wordt overbelastingsresolutie toegepast op de methoden om de meest toepasselijke methode voor de opgegeven argumentenlijst(en) te kiezen. Als de meest toepasselijke methode een functie is, wordt het resultaat van de aanroepexpressie geclassificeerd als een waarde die is getypt als het retourtype van de functie. Als de meest toepasselijke methode een subroutine is, wordt het resultaat geclassificeerd als ongeldig. Als de meest toepasselijke methode een gedeeltelijke methode is die geen hoofdtekst heeft, wordt de aanroepexpressie genegeerd en wordt het resultaat geclassificeerd als ongeldig.
Voor een vroege aanroepexpressie worden de argumenten geëvalueerd in de volgorde waarin de bijbehorende parameters worden gedeclareerd in de doelmethode. Voor een te laat gebonden toegangsexpressie voor leden worden ze geëvalueerd in de volgorde waarin ze worden weergegeven in de toegangsexpressie voor leden: zie Sectie Late-Bound Expressies.
Oplossing van overbelaste methoden:
Voor overbelastingsoplossing, specificiteit van leden/typen op basis van een lijst met argumenten, algemeenheid, toepasbaarheid op lijst met argumenten, het doorgeven van argumenten en het kiezen van argumenten voor optionele parameters, voorwaardelijke methoden en type argumentdeductie: zie Sectie overbelastingsresolutie.
Indexexpressies
Een indexexpressie resulteert in een matrixelement of classificeert een eigenschapsgroep opnieuw in een eigenschapstoegang. Een indexexpressie bestaat uit, in volgorde, een expressie, een haakje openen, een lijst met indexargumenten en een haakje sluiten.
IndexExpression
: Expression OpenParenthesis ArgumentList? CloseParenthesis
;
Het doel van de indexexpressie moet worden geclassificeerd als een eigenschapsgroep of een waarde. Een indexexpressie wordt als volgt verwerkt:
Als de doelexpressie is geclassificeerd als een waarde en als het type geen matrixtype is,
ObjectofSystem.Arrayals het type geen standaardeigenschap heeft. De index wordt uitgevoerd op een eigenschapsgroep die alle standaardeigenschappen van het type vertegenwoordigt. Hoewel het niet geldig is om een parameterloze standaardeigenschap in Visual Basic te declareren, kunnen andere talen toestaan om een dergelijke eigenschap te declareren. Als gevolg hiervan is het indexeren van een eigenschap zonder argumenten toegestaan.Als de expressie resulteert in een waarde van een matrixtype, moet het aantal argumenten in de argumentenlijst hetzelfde zijn als de rangschikking van het matrixtype en mag dit geen benoemde argumenten bevatten. Als een van de indexen tijdens runtime ongeldig is, wordt er een
System.IndexOutOfRangeExceptionuitzondering gegenereerd. Elke expressie moet impliciet worden geconverteerd om te typenInteger. Het resultaat van de indexexpressie is de variabele in de opgegeven index en wordt geclassificeerd als een variabele.Als de expressie is geclassificeerd als een eigenschapsgroep, wordt overbelastingsresolutie gebruikt om te bepalen of een van de eigenschappen van toepassing is op de lijst met indexargumenten. Als de eigenschapsgroep slechts één eigenschap bevat die een
Getaccessor heeft en als deze accessor geen argumenten gebruikt, wordt de eigenschapsgroep geïnterpreteerd als een indexexpressie met een lege argumentenlijst. Het resultaat wordt gebruikt als het doel van de huidige indexexpressie. Als er geen eigenschappen van toepassing zijn, treedt er een compilatietijdfout op. Anders resulteert de expressie in een eigenschapstoegang met de bijbehorende doelexpressie (indien van toepassing) van de eigenschapsgroep.Als de expressie is geclassificeerd als een groep met late eigenschappen of als een waarde waarvan het type is
ObjectofSystem.Array, wordt de verwerking van de indexexpressie uitgesteld tot de uitvoeringstijd en de indexering te laat gebonden is. De expressie resulteert in een late-gebonden eigenschapstoegang die is getypt alsObject. De gekoppelde doelexpressie is de doelexpressie, als het een waarde is of de bijbehorende doelexpressie van de eigenschapsgroep. Tijdens runtime wordt de expressie als volgt verwerkt:Als de expressie is geclassificeerd als een groep met late eigenschappen, kan de expressie resulteren in een methodegroep, een eigenschapsgroep of een waarde (als het lid een exemplaar of gedeelde variabele is). Als het resultaat een methodegroep of eigenschapsgroep is, wordt overbelastingsresolutie toegepast op de groep om de juiste methode voor de lijst met argumenten te bepalen. Als overbelastingsresolutie mislukt, wordt er een
System.Reflection.AmbiguousMatchExceptionuitzondering gegenereerd. Vervolgens wordt het resultaat verwerkt als een eigenschapstoegang of als aanroep en wordt het resultaat geretourneerd. Als de aanroep van een subroutine is, isNothinghet resultaat .Als het runtimetype van de doelexpressie een matrixtype is of
System.Array, is het resultaat van de indexexpressie de waarde van de variabele bij de opgegeven index.Anders moet het runtimetype van de expressie een standaardeigenschap hebben en wordt de index uitgevoerd op de eigenschapsgroep die alle standaardeigenschappen voor het type vertegenwoordigt. Als het type geen standaardeigenschap heeft, wordt er een
System.MissingMemberExceptionuitzondering gegenereerd.
Nieuwe expressies
De operator New wordt gebruikt om nieuwe exemplaren van typen te maken. Er zijn vier vormen van New expressies:
Expressies voor het maken van objecten worden gebruikt om nieuwe exemplaren van klassetypen en waardetypen te maken.
Expressies voor het maken van matrices worden gebruikt om nieuwe exemplaren van matrixtypen te maken.
Expressies voor het maken van gedelegeerden (die geen afzonderlijke syntaxis hebben van expressies voor het maken van objecten) worden gebruikt om nieuwe exemplaren van gedelegeerdentypen te maken.
Anonieme expressies voor het maken van objecten worden gebruikt om nieuwe exemplaren van anonieme klassetypen te maken.
NewExpression
: ObjectCreationExpression
| ArrayExpression
| AnonymousObjectCreationExpression
;
Een New expressie wordt geclassificeerd als een waarde en het resultaat is het nieuwe exemplaar van het type.
Object-Creation expressies
Een expressie voor het maken van objecten wordt gebruikt om een nieuw exemplaar van een klassetype of een structuurtype te maken.
ObjectCreationExpression
: 'New' NonArrayTypeName ( OpenParenthesis ArgumentList? CloseParenthesis )?
ObjectCreationExpressionInitializer?
;
ObjectCreationExpressionInitializer
: ObjectMemberInitializer
| ObjectCollectionInitializer
;
ObjectMemberInitializer
: 'With' OpenCurlyBrace FieldInitializerList CloseCurlyBrace
;
FieldInitializerList
: FieldInitializer ( Comma FieldInitializer )*
;
FieldInitializer
: 'Key'? ('.' IdentifierOrKeyword Equals )? Expression
;
ObjectCollectionInitializer
: 'From' CollectionInitializer
;
CollectionInitializer
: OpenCurlyBrace CollectionElementList? CloseCurlyBrace
;
CollectionElementList
: CollectionElement ( Comma CollectionElement )*
;
CollectionElement
: Expression
| CollectionInitializer
;
Het type expressie voor het maken van objecten moet een klassetype, een structuurtype of een typeparameter met een New beperking zijn en kan geen klasse zijn MustInherit . Gezien een expressie voor het maken van een object van het formulier New T(A), waarbij T een klassetype of structuurtype is en A een optionele lijst met argumenten is, bepaalt overbelastingsresolutie de juiste constructor van T aanroepen. Een typeparameter met een New beperking wordt beschouwd als één parameterloze constructor. Als er geen constructor aanroepbaar is, treedt er een compilatietijdfout op; anders resulteert de expressie in het maken van een nieuw exemplaar van het gebruik van T de gekozen constructor. Als er geen argumenten zijn, kunnen de haakjes worden weggelaten.
Wanneer een instantie wordt toegewezen, is afhankelijk van of het exemplaar een klassetype of een waardetype is.
New exemplaren van klassetypen worden gemaakt op de systeem-heap, terwijl nieuwe exemplaren van waardetypen rechtstreeks op de stack worden gemaakt.
Een expressie voor het maken van objecten kan eventueel een lijst met initialisatiefuncties voor leden opgeven na de constructorargumenten. Deze initializers van leden worden voorafgegaan door het trefwoord Withen de initialisatielijst wordt geïnterpreteerd alsof deze zich in de context van een With instructie bevindt. Bijvoorbeeld, op basis van de klasse:
Class Customer
Dim Name As String
Dim Address As String
End Class
De code:
Module Test
Sub Main()
Dim x As New Customer() With { .Name = "Bob Smith", _
.Address = "123 Main St." }
End Sub
End Module
Komt ongeveer overeen met:
Module Test
Sub Main()
Dim x, _t1 As Customer
_t1 = New Customer()
With _t1
.Name = "Bob Smith"
.Address = "123 Main St."
End With
x = _t1
End Sub
End Module
Elke initialisatiefunctie moet een naam opgeven die moet worden toegewezen en de naam moet een niet-exemplaarvariabeleReadOnly of eigenschap zijn van het type dat wordt samengesteld. De lidtoegang is niet te laat gebonden als het type dat wordt gemaakt.Object Initializers gebruiken mogelijk niet het Key trefwoord. Elk lid in een type kan slechts eenmaal worden geïnitialiseerd. De initialisatie-expressies kunnen echter naar elkaar verwijzen. Voorbeeld:
Module Test
Sub Main()
Dim x As New Customer() With { .Name = "Bob Smith", _
.Address = .Name & " St." }
End Sub
End Module
De initializers worden van links naar rechts toegewezen, dus als een initialisatiefunctie verwijst naar een lid dat nog niet is geïnitialiseerd, ziet deze welke waarde de instantievariabele heeft nadat de constructor is uitgevoerd:
Module Test
Sub Main()
' The value of Address will be " St." since Name has not been
' assigned yet.
Dim x As New Customer() With { .Address = .Name & " St." }
End Sub
End Module
Initializers kunnen worden genest:
Class Customer
Dim Name As String
Dim Address As Address
Dim Age As Integer
End Class
Class Address
Dim Street As String
Dim City As String
Dim State As String
Dim ZIP As String
End Class
Module Test
Sub Main()
Dim c As New Customer() With { _
.Name = "John Smith", _
.Address = New Address() With { _
.Street = "23 Main St.", _
.City = "Peoria", _
.State = "IL", _
.ZIP = "13934" }, _
.Age = 34 }
End Sub
End Module
Als het type dat wordt gemaakt een verzamelingstype is en een instantiemethode heeft met de naam Add (inclusief extensiemethoden en gedeelde methoden), kan de expressie voor het maken van objecten een initialisatie-voorvoegsel van een verzameling opgeven dat door het trefwoord Fromwordt voorafgegaan. Een expressie voor het maken van objecten kan niet zowel een initialisatiefunctie voor leden als een initialisatiefunctie voor verzamelingen opgeven. Elk element in de initialisatiefunctie voor verzamelingen wordt doorgegeven als argument aan een aanroep van de Add functie. Voorbeeld:
Dim list = New List(Of Integer)() From { 1, 2, 3, 4 }
is gelijk aan:
Dim list = New List(Of Integer)()
list.Add(1)
list.Add(2)
list.Add(3)
Als een element een initialisatiefunctie voor verzamelingen zelf is, wordt elk element van de initialisatiefunctie van de subverzameling als een afzonderlijk argument doorgegeven aan de Add functie. Bijvoorbeeld:
Dim dict = Dictionary(Of Integer, String) From { { 1, "One" },{ 2, "Two" } }
is gelijk aan:
Dim dict = New Dictionary(Of Integer, String)
dict.Add(1, "One")
dict.Add(2, "Two")
Deze uitbreiding wordt altijd uitgevoerd en wordt maar één niveau diep uitgevoerd; daarna worden sub-initializers beschouwd als letterlijke matrices. Voorbeeld:
' Error: List(Of T) does not have an Add method that takes two parameters.
Dim list = New List(Of Integer())() From { { 1, 2 }, { 3, 4 } }
' OK, this initializes the dictionary with (Integer, Integer()) pairs.
Dim dict = New Dictionary(Of Integer, Integer())() From _
{ { 1, { 2, 3 } }, { 3, { 4, 5 } } }
Matrixexpressies
Een matrixexpressie wordt gebruikt om een nieuw exemplaar van een matrixtype te maken. Er zijn twee typen matrixexpressies: expressies voor het maken van matrices en letterlijke matrices.
Expressies voor het maken van arrays
Als er een initialisatieaanpassingsmodifier voor matrixgrootte wordt opgegeven, wordt het resulterende matrixtype afgeleid door elk van de afzonderlijke argumenten uit de lijst met initialisatieargumenten voor matrixgrootte te verwijderen. De waarde van elk argument bepaalt de bovengrens van de bijbehorende dimensie in het zojuist toegewezen matrixexemplaren. Als de expressie een niet-lege initialisatiefunctie voor verzamelingen heeft, moet elk argument in de lijst met argumenten een constante zijn en moeten de rang- en dimensielengten die zijn opgegeven door de expressielijst overeenkomen met die van de initialisatiefunctie van de verzameling.
Dim a() As Integer = New Integer(2) {}
Dim b() As Integer = New Integer(2) { 1, 2, 3 }
Dim c(,) As Integer = New Integer(1, 2) { { 1, 2, 3 } , { 4, 5, 6 } }
' Error, length/initializer mismatch.
Dim d() As Integer = New Integer(2) { 0, 1, 2, 3 }
Als er geen aanpassingsfunctie voor de initialisatie van de matrixgrootte wordt opgegeven, moet de typenaam een matrixtype zijn en moet de initialisatiefunctie voor verzamelingen leeg zijn of hetzelfde aantal nestniveaus hebben als de rang van het opgegeven matrixtype. Alle elementen in het binnenste nestniveau moeten impliciet worden omgezet in het elementtype van de matrix en moeten worden geclassificeerd als een waarde. Het aantal elementen in elke geneste initialisatiefunctie voor verzamelingen moet altijd consistent zijn met de grootte van de andere verzamelingen op hetzelfde niveau. De afzonderlijke dimensielengten worden afgeleid van het aantal elementen in elk van de bijbehorende nestniveaus van de initialisatiefunctie van de verzameling. Als de initialisatiefunctie voor de verzameling leeg is, is de lengte van elke dimensie nul.
Dim e() As Integer = New Integer() { 1, 2, 3 }
Dim f(,) As Integer = New Integer(,) { { 1, 2, 3 } , { 4, 5, 6 } }
' Error: Inconsistent numbers of elements!
Dim g(,) As Integer = New Integer(,) { { 1, 2 }, { 4, 5, 6 } }
' Error: Inconsistent levels of nesting!
Dim h(,) As Integer = New Integer(,) { 1, 2, { 3, 4 } }
Het buitenste nestniveau van een verzamelingsinitiator komt overeen met de meest linkse dimensie van een matrix en het binnenste nestniveau komt overeen met de meest rechtse dimensie. Het voorbeeld:
Dim array As Integer(,) = _
{ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }, { 8, 9 } }
Komt overeen met het volgende:
Dim array(4, 1) As Integer
array(0, 0) = 0: array(0, 1) = 1
array(1, 0) = 2: array(1, 1) = 3
array(2, 0) = 4: array(2, 1) = 5
array(3, 0) = 6: array(3, 1) = 7
array(4, 0) = 8: array(4, 1) = 9
Als de initialisatiefunctie voor de verzameling leeg is (dat wil gezegd, een die accolades bevat, maar geen initialisatielijst) en de grenzen van de dimensies van de matrix die wordt geïnitialiseerd, bekend zijn, vertegenwoordigt de lege verzameling initialisatiefunctie een matrixexemplementatie van de opgegeven grootte waarbij alle elementen zijn geïnitialiseerd naar de standaardwaarde van het elementtype. Als de grenzen van de dimensies van de matrix die wordt geïnitialiseerd, niet bekend zijn, vertegenwoordigt de lege initialisatiefunctie voor verzamelingen een matrixexemplaren waarin alle dimensies de grootte nul hebben.
De rang en lengte van elke dimensie van een matrixexemplaren zijn constant voor de gehele levensduur van het exemplaar. Met andere woorden, het is niet mogelijk om de rang van een bestaand matrixexemplaren te wijzigen, en het is ook niet mogelijk om de afmetingen ervan te wijzigen.
Letterlijke matrix
Een letterlijke matrix geeft een matrix aan waarvan het elementtype, de rang en de grenzen worden afgeleid van een combinatie van de expressiecontext en een initialisatiefunctie voor verzamelingen. Dit wordt uitgelegd in sectieexpressie herclassificatie.
ArrayExpression
: ArrayCreationExpression
| ArrayLiteralExpression
;
ArrayCreationExpression
: 'New' NonArrayTypeName ArrayNameModifier CollectionInitializer
;
ArrayLiteralExpression
: CollectionInitializer
;
Voorbeeld:
' array of integers
Dim a = {1, 2, 3}
' array of shorts
Dim b = {1S, 2S, 3S}
' array of shorts whose type is taken from the context
Dim c As Short() = {1, 2, 3}
' array of type Integer(,)
Dim d = {{1, 0}, {0, 1}}
' jagged array of rank ()()
Dim e = {({1, 0}), ({0, 1})}
' error: inconsistent rank
Dim f = {{1}, {2, 3}}
' error: inconsistent rank
Dim g = {1, {2}}
De indeling en vereisten voor de initialisatiefunctie voor verzamelingen in een letterlijke matrix zijn precies hetzelfde als die voor de initialisatiefunctie voor verzamelingen in een expressie voor het maken van een matrix.
Opmerking. Een letterlijke matrix maakt de matrix niet op zichzelf; In plaats daarvan is het de herclassificatie van de expressie in een waarde die ervoor zorgt dat de matrix wordt gemaakt. De conversie CType(new Integer() {1,2,3}, Short()) is bijvoorbeeld niet mogelijk omdat er geen conversie is van Integer() naar Short(); maar de expressie CType({1,2,3},Short()) is mogelijk omdat de letterlijke waarde van de matrix eerst opnieuw wordt geclassificeerd in de expressie voor het maken van de matrix New Short() {1,2,3}.
Delegate-Creation expressies
Er wordt een expressie voor het maken van gemachtigden gebruikt om een nieuw exemplaar van een gedelegeerde te maken. Het argument van een expressie voor het maken van gemachtigden moet een expressie zijn die is geclassificeerd als methodeaanwijzer of een lambda-methode.
Als het argument een methodepointer is, moet een van de methoden waarnaar wordt verwezen door de methodepointer van toepassing zijn op de handtekening van het gemachtigdetype. Een methode M is van toepassing op een type gemachtigde D als:
Mis nietPartialof heeft een lichaam.Beide
MfunctiesDofDzijn een subroutine.MenDhetzelfde aantal parameters hebben.De parametertypen van
Melk hebben een conversie van het type van het overeenkomstige parametertype vanD, en hun modifiers (dat wilByRefByValbijvoorbeeld ) overeenkomst.Het retourtype van
M, indien aanwezig, heeft een conversie naar het retourtypeD.
Als de methodepointer verwijst naar een late toegang, wordt ervan uitgegaan dat de late toegang een functie is met hetzelfde aantal parameters als het type gemachtigde.
Als strikte semantiek niet wordt gebruikt en er slechts één methode wordt verwezen door de methodepointer, maar deze niet van toepassing is vanwege het feit dat er geen parameters zijn en het type gedelegeerde wel, wordt de methode als van toepassing beschouwd en worden de parameters of retourwaarde gewoon genegeerd. Voorbeeld:
Delegate Sub F(x As Integer)
Module Test
Sub M()
End Sub
Sub Main()
' Valid
Dim x As F = AddressOf M
End Sub
End Module
Opmerking. Deze ontspanning is alleen toegestaan wanneer strikte semantiek niet wordt gebruikt vanwege extensiemethoden. Omdat extensiemethoden alleen worden overwogen als een reguliere methode niet van toepassing was, is het mogelijk voor een instantiemethode zonder parameters een extensiemethode te verbergen met parameters voor het doel van gedelegeerde constructie.
Als meer dan één methode waarnaar wordt verwezen door de methodepointer van toepassing is op het type gedelegeerde, wordt overbelastingsresolutie gebruikt om te kiezen tussen de kandidaatmethoden. De typen parameters voor de gemachtigde worden gebruikt als de typen argumenten voor overbelastingsresolutie. Als er geen kandidaat voor de methode het meest van toepassing is, treedt er een compilatietijdfout op. In het volgende voorbeeld wordt de lokale variabele geïnitialiseerd met een gemachtigde die verwijst naar de tweede Square methode, omdat die methode meer van toepassing is op de handtekening en het retourtype .DoubleFunc
Delegate Function DoubleFunc(x As Double) As Double
Module Test
Function Square(x As Single) As Single
Return x * x
End Function
Function Square(x As Double) As Double
Return x * x
End Function
Sub Main()
Dim a As New DoubleFunc(AddressOf Square)
End Sub
End Module
Als de tweede Square methode niet aanwezig was, zou de eerste Square methode zijn gekozen. Als strikte semantiek wordt opgegeven door de compilatieomgeving of door Option Strict, treedt er een compilatiefout op als de meest specifieke methode waarnaar wordt verwezen door de methodepointer smaller is dan de handtekening van de gemachtigde. Een methode M wordt beschouwd als smaller dan een gemachtigde als D :
Een parametertype heeft
Meen widening conversie naar het bijbehorende parametertype vanD.Of, het retourtype, indien van toepassing,
Mheeft een smalle conversie naar het retourtype vanD.
Als typeargumenten zijn gekoppeld aan de methodepointer, worden alleen methoden met hetzelfde aantal typeargumenten overwogen. Als er geen typeargumenten zijn gekoppeld aan de methodepointer, wordt typedeductie gebruikt bij het koppelen van handtekeningen aan een algemene methode. In tegenstelling tot andere normale typedeductie wordt het retourtype van de gemachtigde gebruikt bij het uitstellen van typeargumenten, maar retourtypen worden nog steeds niet meegenomen bij het bepalen van de minst algemene overbelasting. In het volgende voorbeeld ziet u beide manieren om een typeargument op te geven voor een expressie voor het maken van gemachtigden:
Delegate Function D(s As String, i As Integer) As Integer
Delegate Function E() As Integer
Module Test
Public Function F(Of T)(s As String, t1 As T) As T
End Function
Public Function G(Of T)() As T
End Function
Sub Main()
Dim d1 As D = AddressOf f(Of Integer) ' OK, type arg explicit
Dim d2 As D = AddressOf f ' OK, type arg inferred
Dim e1 As E = AddressOf g(Of Integer) ' OK, type arg explicit
Dim e2 As E = AddressOf g ' OK, infer from return
End Sub
End Module
In het bovenstaande voorbeeld is een niet-algemeen gemachtigde type geïnstantieerd met behulp van een algemene methode. Het is ook mogelijk om een exemplaar van een samengesteld gemachtigdetype te maken met behulp van een algemene methode. Voorbeeld:
Delegate Function Predicate(Of U)(u1 As U, u2 As U) As Boolean
Module Test
Function Compare(Of T)(t1 As List(of T), t2 As List(of T)) As Boolean
...
End Function
Sub Main()
Dim p As Predicate(Of List(Of Integer))
p = AddressOf Compare(Of Integer)
End Sub
End Module
Als het argument voor de expressie voor het maken van gemachtigden een lambda-methode is, moet de lambda-methode van toepassing zijn op de handtekening van het type gemachtigde. Een lambda-methode L is van toepassing op een type gemachtigde D als:
Als
Ler parameters zijn,Dheeft u hetzelfde aantal parameters. (AlsLer geen parameters zijn, worden de parametersDgenegeerd.)De parametertypen van
Lelk hebben een conversie naar het type van het overeenkomstige parametertype vanD, en de bijbehorende modifiers (dat wilByRefByValbijvoorbeeld , ) overeenkomst.Als
Ddit een functie is, heeft het retourtypeLeen conversie naar het retourtype .D(AlsDdit een subroutine is, wordt de retourwaardeLgenegeerd.)
Als het parametertype van een parameter van een parameter L wordt weggelaten, wordt het type van de bijbehorende parameter D afgeleid. Als de parameter L matrix- of nullable name modifiers heeft, resulteert een compilatietijdfout. Zodra alle parametertypen L beschikbaar zijn, wordt het type expressie in de lambda-methode afgeleid. Voorbeeld:
Delegate Function F(x As Integer, y As Long) As Long
Module Test
Sub Main()
' b inferred to Integer, c and return type inferred to Long
Dim a As F = Function(b, c) b + c
' e and return type inferred to Integer, f inferred to Long
Dim d As F = Function(e, f) e + CInt(f)
End Sub
End Module
In sommige situaties waarin de gedelegeerde handtekening niet exact overeenkomt met de lambda-methode of methodehandtekening, biedt het .NET Framework mogelijk geen ondersteuning voor het maken van gemachtigden. In dat geval wordt een lambda-methodeexpressie gebruikt om de twee methoden te vinden. Voorbeeld:
Delegate Function IntFunc(x As Integer) As Integer
Module Test
Function SquareString(x As String) As String
Return CInt(x) * CInt(x)
End Function
Sub Main()
' The following two lines are equivalent
Dim a As New IntFunc(AddressOf SquareString)
Dim b As New IntFunc( _
Function(x As Integer) CInt(SquareString(CStr(x))))
End Sub
End Module
Het resultaat van een expressie voor het maken van gedelegeerden is een gemachtigde instantie die verwijst naar de overeenkomende methode met de bijbehorende doelexpressie (indien van toepassing) uit de expressie van de methodepointer. Als de doelexpressie is getypt als een waardetype, wordt het waardetype gekopieerd naar de systeem-heap omdat een gemachtigde alleen naar een methode van een object op de heap kan verwijzen. De methode en het object waarnaar een gemachtigde verwijst, blijven gedurende de gehele levensduur van de gemachtigde constant. Met andere woorden, het is niet mogelijk om het doel of object van een gemachtigde te wijzigen nadat deze is gemaakt.
Anonieme Object-Creation-expressies
Een expressie voor het maken van objecten met initialisatieprogramma's voor leden kan ook de naam van het type volledig weglaten.
AnonymousObjectCreationExpression
: 'New' ObjectMemberInitializer
;
In dat geval wordt een anoniem type samengesteld op basis van de typen en namen van de leden die zijn geïnitialiseerd als onderdeel van de expressie. Voorbeeld:
Module Test
Sub Main()
Dim Customer = New With { .Name = "John Smith", .Age = 34 }
Console.WriteLine(Customer.Name)
End Sub
End Module
Het type dat is gemaakt door een anonieme expressie voor het maken van objecten is een klasse die geen naam heeft, rechtstreeks van Objecten een set eigenschappen heeft met dezelfde naam als de leden die zijn toegewezen in de initialisatielijst van leden. Het type van elke eigenschap wordt afgeleid met behulp van dezelfde regels als deductie van het lokale variabeletype. Gegenereerde anonieme typen overschrijven ToStringook, retourneert een tekenreeksweergave van alle leden en hun waarden. (De exacte indeling van deze tekenreeks valt buiten het bereik van deze specificatie).
De eigenschappen die door het anonieme type worden gegenereerd, zijn standaard lezen/schrijven. Het is mogelijk om een eigenschap van een anoniem type als alleen-lezen te markeren met behulp van de Key wijzigingsfunctie. De Key wijzigingsfunctie geeft aan dat het veld kan worden gebruikt om de waarde te identificeren die het anonieme type vertegenwoordigt. Naast het maken van de eigenschap alleen-lezen, zorgt het ook ervoor dat het anonieme type wordt overschreven Equals en GetHashCode de interface System.IEquatable(Of T) wordt geïmplementeerd (invullen van het anonieme type voor T). De leden worden als volgt gedefinieerd:
Function Equals(obj As Object) As Boolean en Function Equals(val As T) As Boolean worden geïmplementeerd door te valideren dat de twee exemplaren van hetzelfde type zijn en vervolgens elk Key lid vergelijken met behulp van Object.Equals. Als alle Key leden gelijk zijn, retourneert Equals , Equals retourneert FalseTrueanders .
Function GetHashCode() As Integer wordt zodanig geïmplementeerd dat als Equals het waar is voor twee exemplaren van het anonieme type, dezelfde GetHashCode waarde wordt geretourneerd. De hash begint met een seed-waarde en vermenigvuldigt vervolgens voor elk Key lid de hash met 31 en voegt de hashwaarde van het Key lid toe (opgegeven door GetHashCode) als het lid geen verwijzingstype of null-waardetype is met de waarde van Nothing.
Bijvoorbeeld het type dat is gemaakt in de instructie:
Dim zipState = New With { Key .ZipCode = 98112, .State = "WA" }
maakt een klasse die er ongeveer als volgt uitziet (hoewel de exacte implementatie kan variëren):
Friend NotInheritable Class $Anonymous1
Implements IEquatable(Of $Anonymous1)
Private ReadOnly _zipCode As Integer
Private _state As String
Public Sub New(zipCode As Integer, state As String)
_zipCode = zipcode
_state = state
End Sub
Public ReadOnly Property ZipCode As Integer
Get
Return _zipCode
End Get
End Property
Public Property State As String
Get
Return _state
End Get
Set (value As Integer)
_state = value
End Set
End Property
Public Overrides Function Equals(obj As Object) As Boolean
Dim val As $Anonymous1 = TryCast(obj, $Anonymous1)
Return Equals(val)
End Function
Public Overloads Function Equals(val As $Anonymous1) As Boolean _
Implements IEquatable(Of $Anonymous1).Equals
If val Is Nothing Then
Return False
End If
If Not Object.Equals(_zipCode, val._zipCode) Then
Return False
End If
Return True
End Function
Public Overrides Function GetHashCode() As Integer
Dim hash As Integer = 0
hash = hash Xor _zipCode.GetHashCode()
Return hash
End Function
Public Overrides Function ToString() As String
Return "{ Key .ZipCode = " & _zipCode & ", .State = " & _state & " }"
End Function
End Class
Ter vereenvoudiging van de situatie waarin een anoniem type wordt gemaakt op basis van de velden van een ander type, kunnen veldnamen rechtstreeks worden afgeleid uit expressies in de volgende gevallen:
Met een eenvoudige naamexpressie
xwordt de naamxafgeleid.De naam
ywordt afgeleid door een toegangsexpressiex.yvoor leden.Met een opzoekexpressie
x!yvoor woordenlijst wordt de naamyafgeleid.Een aanroep- of indexexpressie zonder argumenten
x()afleiden de naamx.Met een XML-lidtoegangsexpressie
x.<y>wordtx...<y>x.@yde naamyafgeleid.Een XML-lidtoegangsexpressie die het doel is van een toegangsexpressie
x.<y>.zvoor leden, bepaalt de naamz.Een XML-lidtoegangsexpressie die het doel is van een aanroep- of indexexpressie zonder argumenten
x.<y>.z(), bepaalt de naamz.Een XML-lidtoegangsexpressie die het doel is van een aanroep- of indexexpressie
x.<y>(0), bepaalt de naamy.
De initialisatiefunctie wordt geïnterpreteerd als een toewijzing van de expressie aan de uitgestelde naam. De volgende initialisaties zijn bijvoorbeeld gelijkwaardig:
Class Address
Public Street As String
Public City As String
Public State As String
Public ZIP As String
End Class
Class C1
Sub Test(a As Address)
Dim cityState1 = New With { .City = a.City, .State = a.State }
Dim cityState2 = New With { a.City, a.State }
End Sub
End Class
Als een lidnaam wordt afgeleid die conflicteert met een bestaand lid van het type, zoals GetHashCode, treedt er een compilatietijdfout op. In tegenstelling tot reguliere initialisatieprogramma's voor leden, staan anonieme expressies voor het maken van objecten geen kringverwijzingen toe of verwijzen ze naar een lid voordat deze is geïnitialiseerd. Voorbeeld:
Module Test
Sub Main()
' Error: Circular references
Dim x = New With { .a = .b, .b = .a }
' Error: Referring to .b before it has been assigned to
Dim y = New With { .a = .b, .b = 10 }
' Error: Referring to .a before it has been assigned to
Dim z = New With { .a = .a }
End Sub
End Module
Als twee anonieme expressies voor het maken van klassen plaatsvinden binnen dezelfde methode en dezelfde resulterende vorm opleveren, als de volgorde van de eigenschap, eigenschapsnamen en eigenschapstypen allemaal overeenkomen, verwijzen ze beide naar dezelfde anonieme klasse. Het methodebereik van een exemplaar of een gedeelde lidvariabele met een initialisatiefunctie is de constructor waarin de variabele wordt geïnitialiseerd.
Opmerking. Het is mogelijk dat een compiler ervoor kan kiezen om anonieme typen verder samen te stellen, zoals op assemblyniveau, maar dit kan op dit moment niet worden vertrouwd.
Cast-expressies
Een cast-expressie coërt een expressie naar een bepaald type. Specifieke cast-trefwoorden dwingen expressies in de primitieve typen. Drie algemene cast-trefwoorden, CTypeTryCast enDirectCast, dwingen een expressie tot een type.
CastExpression
: 'DirectCast' OpenParenthesis Expression Comma TypeName CloseParenthesis
| 'TryCast' OpenParenthesis Expression Comma TypeName CloseParenthesis
| 'CType' OpenParenthesis Expression Comma TypeName CloseParenthesis
| CastTarget OpenParenthesis Expression CloseParenthesis
;
CastTarget
: 'CBool' | 'CByte' | 'CChar' | 'CDate' | 'CDec' | 'CDbl' | 'CInt'
| 'CLng' | 'CObj' | 'CSByte' | 'CShort' | 'CSng' | 'CStr' | 'CUInt'
| 'CULng' | 'CUShort'
;
DirectCast en TryCast speciale gedragingen hebben. Daarom ondersteunen ze alleen systeemeigen conversies. Daarnaast kan het doeltype in een TryCast expressie geen waardetype zijn. Door de gebruiker gedefinieerde conversieoperators worden niet overwogen wanneer DirectCast of TryCast wordt gebruikt. (Opmerking. De conversieset die DirectCast en TryCast ondersteuning worden beperkt omdat ze 'systeemeigen CLR'-conversies implementeren. Het doel is DirectCast om de functionaliteit van de instructie 'unbox' te bieden, terwijl het doel TryCast is om de functionaliteit van de instructie 'isinst' te bieden. Omdat ze worden toegewezen aan CLR-instructies, zouden ondersteunende conversies die niet rechtstreeks worden ondersteund door de CLR het beoogde doel verslaan.)
DirectCast converteert expressies die als Object anders zijn getypt dan CType. Bij het converteren van een expressie van het type Object waarvan het uitvoeringstijdtype een primitief waardetype is, DirectCast genereert u een System.InvalidCastException uitzondering als het opgegeven type niet hetzelfde is als het runtimetype van de expressie of een System.NullReferenceException als de expressie resulteert in Nothing. (Opmerking. Zoals hierboven vermeld, DirectCast wordt direct toegewezen aan de CLR-instructie 'unbox' wanneer het type van de expressie is Object. Verandert daarentegen CType in een aanroep van een runtime-helper om de conversie uit te voeren, zodat conversies tussen primitieve typen kunnen worden ondersteund. In het geval dat een Object expressie wordt geconverteerd naar een primitief waardetype en het type van het werkelijke exemplaar overeenkomt met het doeltype, DirectCast is aanzienlijk sneller dan CType.)
TryCast converteert expressies, maar genereert geen uitzondering als de expressie niet kan worden geconverteerd naar het doeltype. In plaats daarvan TryCast resulteert dit in Nothing als de expressie niet kan worden geconverteerd tijdens runtime. (Opmerking. Zoals hierboven vermeld, TryCast wijst u rechtstreeks toe op de CLR-instructie "isinst". Door de typecontrole en de conversie in één bewerking te combineren, TryCast kan het goedkoper zijn dan een TypeOf ... Is en dan een CType.)
Voorbeeld:
Interface ITest
Sub Test()
End Interface
Module Test
Sub Convert(o As Object)
Dim i As ITest = TryCast(o, ITest)
If i IsNot Nothing Then
i.Test()
End If
End Sub
End Module
Als er geen conversie bestaat van het type expressie naar het opgegeven type, treedt er een compilatietijdfout op. Anders wordt de expressie geclassificeerd als een waarde en is het resultaat de waarde die door de conversie wordt geproduceerd.
Operatorexpressies
Er zijn twee soorten operators.
Unary-operatoren nemen één operand en gebruiken voorvoegsel notatie (bijvoorbeeld -x).
Binaire operators nemen twee operanden en gebruiken infix-notatie (bijvoorbeeld x + y). Met uitzondering van de relationele operators, die altijd resulteren in Boolean, resulteert een operator die is gedefinieerd voor een bepaald type in dat type. De operanden naar een operator moeten altijd worden geclassificeerd als een waarde; het resultaat van een operatorexpressie wordt geclassificeerd als een waarde.
OperatorExpression
: ArithmeticOperatorExpression
| RelationalOperatorExpression
| LikeOperatorExpression
| ConcatenationOperatorExpression
| ShortCircuitLogicalOperatorExpression
| LogicalOperatorExpression
| ShiftOperatorExpression
| AwaitOperatorExpression
;
Operatorprioriteit en associativiteit
Wanneer een expressie meerdere binaire operators bevat, bepaalt de prioriteit van de operators de volgorde waarin de afzonderlijke binaire operators worden geëvalueerd. De expressie x + y * z wordt bijvoorbeeld geëvalueerd omdat x + (y * z) de * operator een hogere prioriteit heeft dan de + operator. De volgende tabel bevat de binaire operatoren in aflopende volgorde van prioriteit:
| Categorie | Bedieners |
|---|---|
| Primair | Alle expressies die geen operator zijn |
| Wachten | Await |
| Exponentiatie | ^ |
| Unary negation |
+, - |
| Multiplicatieve |
*, / |
| Deling van gehele getallen | \ |
| Modulus | Mod |
| Toevoeging |
+, - |
| Samenvoegen | & |
| Verschuiving |
<<, >> |
| Relationeel |
=, , <<>, >, , <=, >=, IsLikeIsNot |
| Logische NIET | Not |
| Logische AND |
And, AndAlso |
| Logische OR |
Or, OrElse |
| Logische XOR | Xor |
Wanneer een expressie twee operators met dezelfde prioriteit bevat, bepaalt de associativiteit van de operators de volgorde waarin de bewerkingen worden uitgevoerd. Alle binaire operatoren zijn links-associatief, wat betekent dat bewerkingen van links naar rechts worden uitgevoerd. Prioriteit en associativiteit kunnen worden beheerd met behulp van haakjes expressies.
Objectoperands
Naast de reguliere typen die door elke operator worden ondersteund, ondersteunen alle operators operanden van het type Object. Operators die op operanden worden toegepast Object , worden op dezelfde manier verwerkt als methode-aanroepen op Object waarden: een aanroep van een late methode kan worden gekozen. In dat geval bepaalt het runtimetype van de operanden, in plaats van het type compileertijd, de geldigheid en het type van de bewerking. Als strikte semantiek wordt opgegeven door de compilatieomgeving of door Option Strictoperators met operanden van het typeObject, veroorzaakt een compilatietijdfout, met uitzondering van de TypeOf...IsIs en IsNot operators.
Wanneer de operatoromzetting bepaalt dat een bewerking laat gebonden moet worden uitgevoerd, is het resultaat van de bewerking het resultaat van het toepassen van de operator op de operandentypen als de runtimetypen van de operanden typen zijn die door de operator worden ondersteund. De waarde Nothing wordt behandeld als de standaardwaarde van het type van de andere operand in een binaire operatorexpressie. In een unaire operatorexpressie of als beide operanden Nothing zich in een binaire operatorexpressie bevinden, is Integer het type van de bewerking of het enige resultaattype van de operator, als de operator niet resulteert in Integer. Het resultaat van de bewerking wordt altijd teruggezet naar Object. Als de operandtypen geen geldige operator hebben, wordt er een System.InvalidCastException uitzondering gegenereerd. Conversies tijdens runtime worden uitgevoerd, ongeacht of ze impliciet of expliciet zijn.
Als het resultaat van een binaire numerieke bewerking een overloopuitzondering zou opleveren (ongeacht of de controle van gehele getallen overloop is ingeschakeld of uitgeschakeld), wordt het resultaattype indien mogelijk gepromoveerd naar het volgende bredere numerieke type. Denk bijvoorbeeld aan de volgende code:
Module Test
Sub Main()
Dim o As Object = CObj(CByte(2)) * CObj(CByte(255))
Console.WriteLine(o.GetType().ToString() & " = " & o)
End Sub
End Module
Het volgende resultaat wordt afgedrukt:
System.Int16 = 512
Als er geen breder numeriek type beschikbaar is voor het opslaan van het getal, wordt er een System.OverflowException uitzondering gegenereerd.
Operatoromzetting
Bij een operatortype en een set operanden bepaalt de operatoromzetting welke operator moet worden gebruikt voor de operanden. Bij het oplossen van operators wordt eerst rekening gehouden met door de gebruiker gedefinieerde operators, met behulp van de volgende stappen:
Ten eerste worden alle kandidaat-operators verzameld. De kandidaat-operators zijn alle door de gebruiker gedefinieerde operators van het specifieke operatortype in het brontype en alle door de gebruiker gedefinieerde operators van het specifieke type in het doeltype. Als het brontype en het doeltype gerelateerd zijn, worden algemene operators slechts één keer beschouwd.
Vervolgens wordt overbelastingsresolutie toegepast op de operators en operanden om de meest specifieke operator te selecteren. In het geval van binaire operators kan dit leiden tot een late aanroep.
Bij het verzamelen van de kandidaat-operators voor een type T?worden in plaats daarvan de operators van het type T gebruikt.
TAlle door de gebruiker gedefinieerde operators waarvoor alleen niet-nullbare waardetypen zijn betrokken, worden ook opgeheven. Een lifted operator maakt gebruik van de null-versie van alle waardetypen, met uitzondering van de retourtypen IsTrue en IsFalse (die moeten zijn Boolean). Lifted operators worden geëvalueerd door de operanden te converteren naar hun niet-nullable versie, vervolgens de door de gebruiker gedefinieerde operator te evalueren en vervolgens het resultaattype te converteren naar de null-versie. Als etheroperand is, is Nothinghet resultaat van de expressie een waarde van Nothing getypt als de null-versie van het resultaattype. Voorbeeld:
Structure T
...
End Structure
Structure S
Public Shared Operator +(ByVal op1 As S, ByVal op2 As T) As T
...
End Operator
End Structure
Module Test
Sub Main()
Dim x As S?
Dim y, z As T?
' Valid, as S + T = T is lifted to S? + T? = T?
z = x + y
End Sub
End Module
Als de operator een binaire operator is en een van de operanden een verwijzingstype is, wordt de operator ook opgeheven, maar elke binding met de operator veroorzaakt een fout. Voorbeeld:
Structure S1
Public F1 As Integer
Public Shared Operator +(left As S1, right As String) As S1
...
End Operator
End Structure
Module Test
Sub Main()
Dim a? As S1
Dim s As String
' Error: '+' is not defined for S1? and String
a = a + s
End Sub
End Module
Opmerking. Deze regel bestaat omdat er rekening is gehouden met het feit of we referentietypen voor null-doorgifte in een toekomstige versie willen toevoegen, in welk geval het gedrag in het geval van binaire operators tussen de twee typen zou veranderen.
Net als bij conversies hebben door de gebruiker gedefinieerde operators altijd de voorkeur boven lifted operators.
Bij het oplossen van overbelaste operators kunnen er verschillen zijn tussen klassen die zijn gedefinieerd in Visual Basic en de klassen die in andere talen zijn gedefinieerd:
In andere talen,
NotenAndOrmogelijk overbelast, zowel als logische operatoren als bitsgewijze operatoren. Bij het importeren uit een externe assembly wordt een van beide formulieren geaccepteerd als een geldige overbelasting voor deze operators. Voor een type dat zowel logische als bitwise operators definieert, wordt alleen de bitsgewijze implementatie overwogen.In andere talen kunnen
>><<zowel als ondertekende operators als niet-ondertekende operators worden overbelast. Bij het importeren uit een externe assembly wordt een van beide formulieren geaccepteerd als een geldige overbelasting. Voor een type dat zowel ondertekende als niet-ondertekende operators definieert, wordt alleen de ondertekende implementatie overwogen.Als er geen door de gebruiker gedefinieerde operator het meest specifiek is voor de operanden, worden intrinsieke operators overwogen. Als er geen intrinsieke operator is gedefinieerd voor de operanden en een van beide operanden het type Object heeft, wordt de operator laat gebonden opgelost; anders treedt er een compilatietijdfout op.
In eerdere versies van Visual Basic, als er precies één operand van het type Object was, en er geen toepasselijke door de gebruiker gedefinieerde operators en geen toepasselijke intrinsieke operators waren, was het een fout. Vanaf Visual Basic 11 wordt deze nu later opgelost. Voorbeeld:
Module Module1
Sub Main()
Dim p As Object = Nothing
Dim U As New Uri("http://www.microsoft.com")
Dim j = U * p ' is now resolved late-bound
End Sub
End Module
Een type T met een intrinsieke operator definieert ook diezelfde operator voor T?. Het resultaat van de operator op T? is hetzelfde als voor T, behalve dat als een van beide operanden het Nothingresultaat van de operator is Nothing (dat wil gezegd de null-waarde worden doorgegeven). Voor het oplossen van het type bewerking wordt het ? verwijderd uit operanden die deze hebben, wordt het type van de bewerking bepaald en wordt er een ? toegevoegd aan het type bewerking als een van de operanden null-waardetypen zijn. Voorbeeld:
Dim v1? As Integer = 10
Dim v2 As Long = 20
' Type of operation will be Long?
Console.WriteLine(v1 + v2)
Elke operator vermeldt de intrinsieke typen waarvoor deze is gedefinieerd en het type bewerking dat wordt uitgevoerd op basis van de operandtypen. Het resultaat van het type van een intrinsieke bewerking volgt deze algemene regels:
Als alle operanden van hetzelfde type zijn en de operator voor het type is gedefinieerd, treedt er geen conversie op en wordt de operator voor dat type gebruikt.
Elke operand waarvan het type niet is gedefinieerd voor de operator wordt geconverteerd met behulp van de volgende stappen en de operator wordt omgezet op basis van de nieuwe typen:
De operand wordt geconverteerd naar het volgende breedste type dat is gedefinieerd voor zowel de operator als de operand en waarnaar het impliciet converteerbaar is.
Als er geen dergelijk type is, wordt de operand geconverteerd naar het eerstvolgende smalste type dat is gedefinieerd voor zowel de operator als de operand en waarnaar deze impliciet converteerbaar is.
Als er geen dergelijk type is of de conversie niet kan optreden, treedt er een compilatietijdfout op.
Anders worden de operanden geconverteerd naar de bredere operandtypen en wordt de operator voor dat type gebruikt. Als het smallere operandtype niet impliciet kan worden geconverteerd naar het bredere operatortype, treedt er een compilatietijdfout op.
Ondanks deze algemene regels zijn er echter een aantal speciale gevallen aangeroepen in de tabel met operatorresultaten.
Opmerking. Om opmaakredenen worden de vooraf gedefinieerde namen afgekort door de operatortabellen tot de eerste twee tekens. Dus 'By' is, 'UI' isByteUInteger, 'St' isString, enzovoort' betekent dat er geen bewerking is gedefinieerd voor de opgegeven operandtypen.
Rekenkundige operatoren
De *operatoren , , /\, ^, en -Mod+operators zijn de rekenkundige operatoren.
ArithmeticOperatorExpression
: UnaryPlusExpression
| UnaryMinusExpression
| AdditionOperatorExpression
| SubtractionOperatorExpression
| MultiplicationOperatorExpression
| DivisionOperatorExpression
| ModuloOperatorExpression
| ExponentOperatorExpression
;
Rekenkundige bewerkingen met drijvende komma kunnen met een hogere precisie worden uitgevoerd dan het resultaattype van de bewerking. Sommige hardwarearchitecturen ondersteunen bijvoorbeeld een 'uitgebreid' of 'lang dubbel' drijvendekommatype met een groter bereik en een grotere precisie dan het Double type, en voeren impliciet alle drijvendekommabewerkingen uit met dit type hogere precisie. Hardwarearchitecturen kunnen worden gemaakt om drijvendekommabewerkingen uit te voeren met minder precisie, alleen tegen overmatige kosten in prestaties; In plaats van een implementatie te vereisen om zowel prestaties als precisie te verliezen, kan met Visual Basic het type hogere precisie worden gebruikt voor alle drijvendekommabewerkingen. Afgezien van het leveren van nauwkeurigere resultaten, heeft dit zelden meetbare effecten. In expressies van het formulier x * y / z, waarbij de vermenigvuldiging echter een resultaat produceert dat zich buiten het Double bereik bevindt, maar de volgende deling het tijdelijke resultaat weer in het Double bereik brengt, kan het feit dat de expressie wordt geëvalueerd in een indeling met een hoger bereik ertoe leiden dat een eindig resultaat wordt geproduceerd in plaats van oneindig.
Unary Plus-operator
UnaryPlusExpression
: '+' Expression
;
De unaire plus-operator wordt gedefinieerd voor de Bytetypen , , SByte, ShortUShort, ULongIntegerLongSingleUInteger, , Doubleen Decimal typen.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Sh | SB | Bij | Sh | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob |
Unary Minus Operator
UnaryMinusExpression
: '-' Expression
;
De unaire min-operator wordt gedefinieerd voor de volgende typen:
SByte, Short, Integeren Long. Het resultaat wordt berekend door de operand af te trekken van nul. Als controle op gehele getallen overloop is ingeschakeld en de waarde van de operand het maximum negatief SByteis, Shortof Integer, wordt Longer een System.OverflowException uitzondering gegenereerd. Als de waarde van de operand anders het maximum negatief SByteis, Short, Integerof Long, is het resultaat dezelfde waarde en wordt de overloop niet gerapporteerd.
Single en Double. Het resultaat is de waarde van de operand met het bijbehorende teken omgedraaid, inclusief de waarden 0 en Infinity. Als de operand NaN is, is het resultaat ook NaN.
Decimal. Het resultaat wordt berekend door de operand af te trekken van nul.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Sh | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob |
Operator voor optellen
De opteloperator berekent de som van de twee operanden.
AdditionOperatorExpression
: Expression '+' LineTerminator? Expression
;
De toevoegingsoperator is gedefinieerd voor de volgende typen:
Byte,SByte,UShort,Short,UInteger,Integer,ULongenLong. Als de controle van een overloop van gehele getallen is ingeschakeld en de som buiten het bereik van het resultaattype valt, wordt er eenSystem.OverflowExceptionuitzondering gegenereerd. Anders worden overloop niet gerapporteerd en worden belangrijke bits van het resultaat verwijderd.SingleenDouble. De som wordt berekend volgens de regels van IEEE 754-rekenkundige berekeningen.Decimal. Als de resulterende waarde te groot is om weer te geven in de decimale notatie, wordt er eenSystem.OverflowExceptionuitzondering gegenereerd. Als de resultaatwaarde te klein is om weer te geven in de decimale notatie, is het resultaat 0.String. De tweeStringoperanden worden samengevoegd.Date. HetSystem.DateTimetype definieert overbelaste toevoegingsoperatoren. OmdatSystem.DateTimedit gelijk is aan het intrinsiekeDatetype, zijn deze operators ook beschikbaar voor hetDatetype.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Sh | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob |
| SB | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |
| Bij | Bij | Sh | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||
| Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||
| VS | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||
| In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||||
| ui- | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||||
| Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||||||
| UL | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||||||
| De | De | Si | Maak | Err | Err | Maak | Ob | |||||||||
| Si | Si | Maak | Err | Err | Maak | Ob | ||||||||||
| Doen | Maak | Err | Err | Maak | Ob | |||||||||||
| Da | St | Err | St | Ob | ||||||||||||
| Ch | St | St | Ob | |||||||||||||
| St | St | Ob | ||||||||||||||
| Ob | Ob |
Operator voor aftrekken
De aftrekkingsoperator trekt de tweede operand af van de eerste operand.
SubtractionOperatorExpression
: Expression '-' LineTerminator? Expression
;
De aftrekkingsoperator is gedefinieerd voor de volgende typen:
Byte,SByte,UShort,Short,UInteger,Integer,ULongenLong. Als controle op gehele getallen overloop is ingeschakeld en het verschil buiten het bereik van het resultaattype valt, wordt er eenSystem.OverflowExceptionuitzondering gegenereerd. Anders worden overloop niet gerapporteerd en worden belangrijke bits van het resultaat verwijderd.SingleenDouble. Het verschil wordt berekend volgens de regels van IEEE 754-rekenkundige berekeningen.Decimal. Als de resulterende waarde te groot is om weer te geven in de decimale notatie, wordt er eenSystem.OverflowExceptionuitzondering gegenereerd. Als de resultaatwaarde te klein is om weer te geven in de decimale notatie, is het resultaat 0.Date. HetSystem.DateTimetype definieert overbelaste aftrekkingsoperators. OmdatSystem.DateTimedit gelijk is aan het intrinsiekeDatetype, zijn deze operators ook beschikbaar voor hetDatetype.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Sh | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob |
| SB | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |
| Bij | Bij | Sh | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||
| Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||
| VS | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||
| In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||||
| ui- | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||||
| Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||||||
| UL | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||||||
| De | De | Si | Maak | Err | Err | Maak | Ob | |||||||||
| Si | Si | Maak | Err | Err | Maak | Ob | ||||||||||
| Doen | Maak | Err | Err | Maak | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| St | Maak | Ob | ||||||||||||||
| Ob | Ob |
Vermenigvuldigingsoperator
De vermenigvuldigingsoperator berekent het product van twee operanden.
MultiplicationOperatorExpression
: Expression '*' LineTerminator? Expression
;
De vermenigvuldigingsoperator wordt gedefinieerd voor de volgende typen:
Byte,SByte,UShort,Short,UInteger,Integer,ULongenLong. Als controle op overloop op gehele getallen is ingeschakeld en het product zich buiten het bereik van het resultaattype bevindt, wordt er eenSystem.OverflowExceptionuitzondering gegenereerd. Anders worden overloop niet gerapporteerd en worden belangrijke bits van het resultaat verwijderd.SingleenDouble. Het product wordt berekend volgens de regels van IEEE 754-rekenkundige berekeningen.Decimal. Als de resulterende waarde te groot is om weer te geven in de decimale notatie, wordt er eenSystem.OverflowExceptionuitzondering gegenereerd. Als de resultaatwaarde te klein is om weer te geven in de decimale notatie, is het resultaat 0.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Sh | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob |
| SB | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |
| Bij | Bij | Sh | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||
| Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||
| VS | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||
| In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||||
| ui- | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||||
| Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||||||
| UL | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||||||
| De | De | Si | Maak | Err | Err | Maak | Ob | |||||||||
| Si | Si | Maak | Err | Err | Maak | Ob | ||||||||||
| Doen | Maak | Err | Err | Maak | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| St | Maak | Ob | ||||||||||||||
| Ob | Ob |
Operatoren voor delen
Operatoren berekenen het quotiënt van twee operanden. Er zijn twee divisieoperators: de normale operator voor delen (drijvende komma) en de operator voor gehele getallen.
DivisionOperatorExpression
: FPDivisionOperatorExpression
| IntegerDivisionOperatorExpression
;
FPDivisionOperatorExpression
: Expression '/' LineTerminator? Expression
;
IntegerDivisionOperatorExpression
: Expression '\\' LineTerminator? Expression
;
De operator voor de reguliere deling wordt gedefinieerd voor de volgende typen:
SingleenDouble. Het quotiënt wordt berekend volgens de regels van IEEE 754-rekenkundige bewerkingen.Decimal. Als de waarde van de rechteroperand nul is, wordt er eenSystem.DivideByZeroExceptionuitzondering gegenereerd. Als de resulterende waarde te groot is om weer te geven in de decimale notatie, wordt er eenSystem.OverflowExceptionuitzondering gegenereerd. Als de resultaatwaarde te klein is om weer te geven in de decimale notatie, is het resultaat nul. De schaal van het resultaat, vóór afronding, is de dichtstbijzijnde schaal naar de voorkeursschaal, waardoor een resultaat gelijk blijft aan het exacte resultaat. De voorkeursschaal is de schaal van de eerste operand minder de schaal van de tweede operand.
Volgens normale operatoroplossingsregels, normale verdeling puur tussen operanden van typen zoals Byte, Short, Integeren Long zou ervoor zorgen dat beide operanden worden geconverteerd naar type Decimal. Bij het uitvoeren van operatorresolutie op de operator van de deling wanneer geen van beide typen is Decimal, Double wordt echter beschouwd als smaller dan Decimal. Deze conventie wordt gevolgd omdat Double deling efficiënter is dan Decimal delen.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | De | Si | Maak | Err | Err | Maak | Ob |
| SB | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | De | Si | Maak | Err | Err | Maak | Ob | |
| Bij | Maak | Maak | Maak | Maak | Maak | Maak | Maak | De | Si | Maak | Err | Err | Maak | Ob | ||
| Sh | Maak | Maak | Maak | Maak | Maak | Maak | De | Si | Maak | Err | Err | Maak | Ob | |||
| VS | Maak | Maak | Maak | Maak | Maak | De | Si | Maak | Err | Err | Maak | Ob | ||||
| In | Maak | Maak | Maak | Maak | De | Si | Maak | Err | Err | Maak | Ob | |||||
| ui- | Maak | Maak | Maak | De | Si | Maak | Err | Err | Maak | Ob | ||||||
| Lo | Maak | Maak | De | Si | Maak | Err | Err | Maak | Ob | |||||||
| UL | Maak | De | Si | Maak | Err | Err | Maak | Ob | ||||||||
| De | De | Si | Maak | Err | Err | Maak | Ob | |||||||||
| Si | Si | Maak | Err | Err | Maak | Ob | ||||||||||
| Doen | Maak | Err | Err | Maak | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| St | Maak | Ob | ||||||||||||||
| Ob | Ob |
De operator voor het delen van gehele getallen wordt gedefinieerd voor Byte, , SByteUShort, Short, UInteger, , Integer, en ULongLong. Als de waarde van de rechteroperand nul is, wordt er een System.DivideByZeroException uitzondering gegenereerd. De deling rondt het resultaat af op nul en de absolute waarde van het resultaat is het grootst mogelijke gehele getal dat kleiner is dan de absolute waarde van het quotiënt van de twee operanden. Het resultaat is nul of positief wanneer de twee operanden hetzelfde teken hebben en nul of negatief wanneer de twee operanden tegengestelde tekens hebben. Als de linkeroperand het maximum negatief SByteis, Shortof Integer, of Longen de rechteroperand een overloop is -1, treedt er een overloop op. Als controle op gehele getallen is ingeschakeld, wordt er een System.OverflowException uitzondering gegenereerd. Anders wordt de overloop niet gerapporteerd en is het resultaat in plaats daarvan de waarde van de linkeroperand.
Opmerking. Omdat de twee operanden voor niet-ondertekende typen altijd nul of positief zijn, is het resultaat altijd nul of positief. Als gevolg van de expressie is altijd kleiner dan of gelijk aan de grootste van de twee operanden, is het niet mogelijk om een overloop uit te voeren. Als zodanig wordt controle op overloop van gehele getallen niet uitgevoerd voor het delen van gehele getallen met twee niet-ondertekende gehele getallen. Het resultaat is het type als dat van de linkeroperand.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Sh | SB | Sh | Sh | In | In | Lo | Lo | Lo | Lo | Lo | Lo | Err | Err | Lo | Ob |
| SB | SB | Sh | Sh | In | In | Lo | Lo | Lo | Lo | Lo | Lo | Err | Err | Lo | Ob | |
| Bij | Bij | Sh | VS | In | UI (Gebruikersinterface) | Lo | UL | Lo | Lo | Lo | Err | Err | Lo | Ob | ||
| Sh | Sh | In | In | Lo | Lo | Lo | Lo | Lo | Lo | Err | Err | Lo | Ob | |||
| VS | VS | In | UI (Gebruikersinterface) | Lo | UL | Lo | Lo | Lo | Err | Err | Lo | Ob | ||||
| In | In | Lo | Lo | Lo | Lo | Lo | Lo | Err | Err | Lo | Ob | |||||
| ui- | UI (Gebruikersinterface) | Lo | UL | Lo | Lo | Lo | Err | Err | Lo | Ob | ||||||
| Lo | Lo | Lo | Lo | Lo | Lo | Err | Err | Lo | Ob | |||||||
| UL | UL | Lo | Lo | Lo | Err | Err | Lo | Ob | ||||||||
| De | Lo | Lo | Lo | Err | Err | Lo | Ob | |||||||||
| Si | Lo | Lo | Err | Err | Lo | Ob | ||||||||||
| Doen | Lo | Err | Err | Lo | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| St | Lo | Ob | ||||||||||||||
| Ob | Ob |
Mod-operator
De Mod operator (modulo) berekent de rest van de verdeling tussen twee operanden.
ModuloOperatorExpression
: Expression 'Mod' LineTerminator? Expression
;
De Mod operator is gedefinieerd voor de volgende typen:
Byte, ,UShortSByte,Short, ,UInteger, enLongIntegerULong. Het resultaat vanx Mod yis de waarde die wordt geproduceerd doorx - (x \ y) * y. Alsynul is, wordt er eenSystem.DivideByZeroExceptionuitzondering gegenereerd. De modulo-operator veroorzaakt nooit een overloop.SingleenDouble. De rest wordt berekend volgens de regels van IEEE 754-rekenkundige berekeningen.Decimal. Als de waarde van de rechteroperand nul is, wordt er eenSystem.DivideByZeroExceptionuitzondering gegenereerd. Als de resulterende waarde te groot is om weer te geven in de decimale notatie, wordt er eenSystem.OverflowExceptionuitzondering gegenereerd. Als de resultaatwaarde te klein is om weer te geven in de decimale notatie, is het resultaat nul.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Sh | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob |
| SB | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |
| Bij | Bij | Sh | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||
| Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||
| VS | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||
| In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||||
| ui- | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||||
| Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||||||
| UL | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||||||
| De | De | Si | Maak | Err | Err | Maak | Ob | |||||||||
| Si | Si | Maak | Err | Err | Maak | Ob | ||||||||||
| Doen | Maak | Err | Err | Maak | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| St | Maak | Ob | ||||||||||||||
| Ob | Ob |
Exponentiëringsoperator
De exponentiatieoperator berekent de eerste operand die is verheven tot de kracht van de tweede operand.
ExponentOperatorExpression
: Expression '^' LineTerminator? Expression
;
De exponentiatieoperator wordt gedefinieerd voor het type Double. De waarde wordt berekend volgens de regels van IEEE 754-rekenkundige berekeningen.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Err | Err | Maak | Ob |
| SB | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Err | Err | Maak | Ob | |
| Bij | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Err | Err | Maak | Ob | ||
| Sh | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Err | Err | Maak | Ob | |||
| VS | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Err | Err | Maak | Ob | ||||
| In | Maak | Maak | Maak | Maak | Maak | Maak | Maak | Err | Err | Maak | Ob | |||||
| ui- | Maak | Maak | Maak | Maak | Maak | Maak | Err | Err | Maak | Ob | ||||||
| Lo | Maak | Maak | Maak | Maak | Maak | Err | Err | Maak | Ob | |||||||
| UL | Maak | Maak | Maak | Maak | Err | Err | Maak | Ob | ||||||||
| De | Maak | Maak | Maak | Err | Err | Maak | Ob | |||||||||
| Si | Maak | Maak | Err | Err | Maak | Ob | ||||||||||
| Doen | Maak | Err | Err | Maak | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| St | Maak | Ob | ||||||||||||||
| Ob | Ob |
Relationele operators
De relationele operators vergelijken waarden met elkaar. De vergelijkingsoperatoren zijn =, <>, <, , >en <=.>=
RelationalOperatorExpression
: Expression '=' LineTerminator? Expression
| Expression '<' '>' LineTerminator? Expression
| Expression '<' LineTerminator? Expression
| Expression '>' LineTerminator? Expression
| Expression '<' '=' LineTerminator? Expression
| Expression '>' '=' LineTerminator? Expression
;
Alle relationele operatoren resulteren in een Boolean waarde.
De relationele operators hebben de volgende algemene betekenis:
De
=operator test of de twee operanden gelijk zijn.De
<>operator test of de twee operanden niet gelijk zijn.De
<operator test of de eerste operand kleiner is dan de tweede operand.De
>operator test of de eerste operand groter is dan de tweede operand.De
<=operator test of de eerste operand kleiner is dan of gelijk is aan de tweede operand.De
>=operator test of de eerste operand groter is dan of gelijk is aan de tweede operand.
De relationele operators worden gedefinieerd voor de volgende typen:
Boolean. De operators vergelijken de waarheidswaarden van de twee operanden.Truewordt beschouwd als kleiner danFalse, die overeenkomt met hun numerieke waarden.Byte,SByte,UShort,Short,UInteger,Integer,ULongenLong. De operators vergelijken de numerieke waarden van de twee integrale operanden.SingleenDouble. De operators vergelijken de operanden volgens de regels van de IEEE 754-standaard.Decimal. De operators vergelijken de numerieke waarden van de twee decimale operanden.Date. De operators retourneren het resultaat van het vergelijken van de twee datum-/tijdwaarden.Char. De operators retourneren het resultaat van het vergelijken van de twee Unicode-waarden.String. De operators retourneren het resultaat van het vergelijken van de twee waarden met behulp van een binaire vergelijking of een tekstvergelijking. De gebruikte vergelijking wordt bepaald door de compilatieomgeving en deOption Compareinstructie. Een binaire vergelijking bepaalt of de numerieke Unicode-waarde van elk teken in elke tekenreeks hetzelfde is. Een tekstvergelijking voert een Unicode-tekstvergelijking uit op basis van de huidige cultuur die wordt gebruikt in .NET Framework. Wanneer u een tekenreeksvergelijking uitvoert, is een null-waarde gelijk aan de letterlijke tekenreeks"".
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Bo | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Bo | Ob |
| SB | SB | Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |
| Bij | Bij | Sh | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||
| Sh | Sh | In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||
| VS | VS | In | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||
| In | In | Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||||
| ui- | UI (Gebruikersinterface) | Lo | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||||
| Lo | Lo | De | De | Si | Maak | Err | Err | Maak | Ob | |||||||
| UL | UL | De | Si | Maak | Err | Err | Maak | Ob | ||||||||
| De | De | Si | Maak | Err | Err | Maak | Ob | |||||||||
| Si | Si | Maak | Err | Err | Maak | Ob | ||||||||||
| Doen | Maak | Err | Err | Maak | Ob | |||||||||||
| Da | Da | Err | Da | Ob | ||||||||||||
| Ch | Ch | St | Ob | |||||||||||||
| St | St | Ob | ||||||||||||||
| Ob | Ob |
Operator liken
De Like operator bepaalt of een tekenreeks overeenkomt met een bepaald patroon.
LikeOperatorExpression
: Expression 'Like' LineTerminator? Expression
;
De Like operator is gedefinieerd voor het String type. De eerste operand is de tekenreeks die wordt vergeleken en de tweede operand is het patroon dat moet worden vergeleken. Het patroon bestaat uit Unicode-tekens. De volgende tekenreeksen hebben speciale betekenissen:
Het teken
?komt overeen met een willekeurig teken.Het teken
*komt overeen met nul of meer tekens.Het teken
#komt overeen met één cijfer (0-9).Een lijst met tekens tussen vierkante haken (
[ab...]) komt overeen met één teken in de lijst.Een lijst met tekens tussen vierkante haken en voorvoegsel door een uitroepteken (
[!ab...]) komt overeen met één teken dat niet in de lijst met tekens staat.Twee tekens in een lijst met tekens, gescheiden door een afbreekstreepje (
-) geven een bereik van Unicode-tekens op die beginnen met het eerste teken en eindigen op het tweede teken. Als het tweede teken zich niet later in de sorteervolgorde bevindt dan het eerste teken, treedt er een runtime-uitzondering op. Een afbreekstreepje dat aan het begin of einde van een lijst met tekens wordt weergegeven, geeft zichzelf aan.
Als u wilt overeenkomen met de speciale tekens, haakjes links ([), vraagteken (?), cijferteken () en sterretje (#*), moeten haakjes deze tussen haakjes zetten. De rechterhaak (]) kan niet worden gebruikt binnen een groep om aan zichzelf te voldoen, maar kan buiten een groep worden gebruikt als afzonderlijk teken. De tekenreeks [] wordt beschouwd als de letterlijke tekenreeks "".
Merk op dat tekenvergelijkingen en volgorde voor tekenlijsten afhankelijk zijn van het type vergelijkingen dat wordt gebruikt. Als binaire vergelijkingen worden gebruikt, zijn tekenvergelijkingen en volgorde gebaseerd op de numerieke Unicode-waarden. Als tekstvergelijkingen worden gebruikt, zijn tekenvergelijkingen en volgorde gebaseerd op de huidige landinstelling die wordt gebruikt in .NET Framework.
In sommige talen vertegenwoordigen speciale tekens in het alfabet twee afzonderlijke tekens en omgekeerd. In verschillende talen wordt bijvoorbeeld het teken æ gebruikt om de tekens a weer te geven en e wanneer deze samen worden weergegeven, terwijl de tekens ^ en O kunnen worden gebruikt om het teken Ôweer te geven. Bij het gebruik van tekstvergelijkingen herkent de Like exploitant dergelijke culturele gelijkwaardigheden. In dat geval komt een exemplaar van één speciaal teken in een patroon of tekenreeks overeen met de equivalente reeks van twee tekens in de andere tekenreeks. Op dezelfde manier komt één speciaal teken in patroon tussen vierkante haken (op zichzelf, in een lijst of in een bereik) overeen met de equivalente reeks van twee tekens in de tekenreeks en omgekeerd.
In een Like expressie waarbij beide operanden zijn Nothing of één operand een intrinsieke conversie naar String en de andere operand is Nothing, Nothing wordt behandeld alsof het de lege letterlijke ""tekenreeks is.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | St | St | St | St | St | St | St | St | St | St | St | St | St | St | St | Ob |
| SB | St | St | St | St | St | St | St | St | St | St | St | St | St | St | Ob | |
| Bij | St | St | St | St | St | St | St | St | St | St | St | St | St | Ob | ||
| Sh | St | St | St | St | St | St | St | St | St | St | St | St | Ob | |||
| VS | St | St | St | St | St | St | St | St | St | St | St | Ob | ||||
| In | St | St | St | St | St | St | St | St | St | St | Ob | |||||
| ui- | St | St | St | St | St | St | St | St | St | Ob | ||||||
| Lo | St | St | St | St | St | St | St | St | Ob | |||||||
| UL | St | St | St | St | St | St | St | Ob | ||||||||
| De | St | St | St | St | St | St | Ob | |||||||||
| Si | St | St | St | St | St | Ob | ||||||||||
| Doen | St | St | St | St | Ob | |||||||||||
| Da | St | St | St | Ob | ||||||||||||
| Ch | St | St | Ob | |||||||||||||
| St | St | Ob | ||||||||||||||
| Ob | Ob |
Samenvoegingsoperator
ConcatenationOperatorExpression
: Expression '&' LineTerminator? Expression
;
De samenvoegingsoperator wordt gedefinieerd voor alle intrinsieke typen, met inbegrip van de null-versies van de intrinsieke waardetypen. Het wordt ook gedefinieerd voor samenvoeging tussen de hierboven genoemde typen en System.DBNull, die worden behandeld als een Nothing tekenreeks. De samenvoegingsoperator converteert alle operanden naar String; in de expressie worden alle conversies die moeten String worden beschouwd als breder, ongeacht of strikte semantiek wordt gebruikt. Een System.DBNull waarde wordt geconverteerd naar de letterlijke waarde Nothing die is getypt als String. Een null-waardetype waarvan de waarde ook wordt Nothing geconverteerd naar de letterlijke Nothing waarde die is getypt, Stringin plaats van een runtimefout te genereren.
Een samenvoegingsbewerking resulteert in een tekenreeks die de samenvoeging is van de twee operanden in volgorde van links naar rechts. De waarde Nothing wordt behandeld alsof deze de letterlijke waarde ""van de lege tekenreeks is.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | St | St | St | St | St | St | St | St | St | St | St | St | St | St | St | Ob |
| SB | St | St | St | St | St | St | St | St | St | St | St | St | St | St | Ob | |
| Bij | St | St | St | St | St | St | St | St | St | St | St | St | St | Ob | ||
| Sh | St | St | St | St | St | St | St | St | St | St | St | St | Ob | |||
| VS | St | St | St | St | St | St | St | St | St | St | St | Ob | ||||
| In | St | St | St | St | St | St | St | St | St | St | Ob | |||||
| ui- | St | St | St | St | St | St | St | St | St | Ob | ||||||
| Lo | St | St | St | St | St | St | St | St | Ob | |||||||
| UL | St | St | St | St | St | St | St | Ob | ||||||||
| De | St | St | St | St | St | St | Ob | |||||||||
| Si | St | St | St | St | St | Ob | ||||||||||
| Doen | St | St | St | St | Ob | |||||||||||
| Da | St | St | St | Ob | ||||||||||||
| Ch | St | St | Ob | |||||||||||||
| St | St | Ob | ||||||||||||||
| Ob | Ob |
Logische operators
De Andoperatoren , Noten XorOroperators worden de logische operatoren genoemd.
LogicalOperatorExpression
: 'Not' Expression
| Expression 'And' LineTerminator? Expression
| Expression 'Or' LineTerminator? Expression
| Expression 'Xor' LineTerminator? Expression
;
De logische operators worden als volgt geëvalueerd:
Voor het
Booleantype:Er wordt een logische
Andbewerking uitgevoerd op de twee operanden.Er wordt een logische
Notbewerking uitgevoerd op de operand.Er wordt een logische
Orbewerking uitgevoerd op de twee operanden.Een logische exclusieve
Orbewerking wordt uitgevoerd op de twee operanden.
Voor
Byte,SByte,UShort,Short, ,UInteger, ,Integer, ,ULongenLongalle geïnventariseerd typen, wordt de opgegeven bewerking uitgevoerd op elke bit van de binaire weergave van de twee operanden):And: De resultaatbit is 1 als beide bits 1 zijn; anders is de resultaat-bit 0.Not: De resultaatbit is 1 als de bit 0 is; anders is de resultaatbit 1.Or: De resultaatbit is 1 als een van beide bits 1 is; anders is de resultaat-bit 0.Xor: De resultaatbit is 1 als een van beide bits 1 is, maar niet beide bits; anders is de resultaatbit 0 (dat wil gezegd: 1Xor0 = 1, 1Xor1 = 0).
Wanneer de logische operators
Andworden opgeheven enOrvoor het typeBoolean?worden opgeheven, worden ze uitgebreid tot booleaanse logica met drie waarden als zodanig:Andresulteert in waar als beide operanden waar zijn; onwaar als een van de operanden onwaar is;Nothinganders.Orresulteert in waar als een van beide operanden waar is; false is beide operanden onwaar;Nothinganders.
Voorbeeld:
Module Test
Sub Main()
Dim x?, y? As Boolean
x = Nothing
y = True
If x Or y Then
' Will execute
End If
End Sub
End Module
Opmerking. In het ideale geval worden de logische operatoren AndOr opgeheven met behulp van drie-waardelogica voor elk type dat kan worden gebruikt in een Boole-expressie (d.w.w.v. een type dat wordt geïmplementeerd IsTrue en IsFalse), op dezelfde manier als AndAlso dat en OrElse kortsluiting voor elk type dat kan worden gebruikt in een Boole-expressie. Helaas wordt het tillen met drie waarden alleen toegepast opBoolean?, dus door de gebruiker gedefinieerde typen die behoefte hebben aan logica met drie waarden, moeten dit handmatig doen door operators te definiëren en Or te gebruiken And voor hun null-versie.
Er zijn geen overloopmogelijkheden bij deze bewerkingen. De operators van het geïnventariseerd type voeren de bitsgewijze bewerking uit op het onderliggende type van het geïnventariseerd type, maar de retourwaarde is het geïnventariseerd type.
Niet bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | SB | Bij | Sh | VS | In | UI (Gebruikersinterface) | Lo | UL | Lo | Lo | Lo | Err | Err | Lo | Ob |
En, of, Xor-bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Bo | SB | Sh | Sh | In | In | Lo | Lo | Lo | Lo | Lo | Lo | Err | Err | Bo | Ob |
| SB | SB | Sh | Sh | In | In | Lo | Lo | Lo | Lo | Lo | Lo | Err | Err | Lo | Ob | |
| Bij | Bij | Sh | VS | In | UI (Gebruikersinterface) | Lo | UL | Lo | Lo | Lo | Err | Err | Lo | Ob | ||
| Sh | Sh | In | In | Lo | Lo | Lo | Lo | Lo | Lo | Err | Err | Lo | Ob | |||
| VS | VS | In | UI (Gebruikersinterface) | Lo | UL | Lo | Lo | Lo | Err | Err | Lo | Ob | ||||
| In | In | Lo | Lo | Lo | Lo | Lo | Lo | Err | Err | Lo | Ob | |||||
| ui- | UI (Gebruikersinterface) | Lo | UL | Lo | Lo | Lo | Err | Err | Lo | Ob | ||||||
| Lo | Lo | Lo | Lo | Lo | Lo | Err | Err | Lo | Ob | |||||||
| UL | UL | Lo | Lo | Lo | Err | Err | Lo | Ob | ||||||||
| De | Lo | Lo | Lo | Err | Err | Lo | Ob | |||||||||
| Si | Lo | Lo | Err | Err | Lo | Ob | ||||||||||
| Doen | Lo | Err | Err | Lo | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| St | Lo | Ob | ||||||||||||||
| Ob | Ob |
Logische operators kortsluiten
De AndAlso en OrElse operators zijn de kortsluitingsversies van de And en Or logische operators.
ShortCircuitLogicalOperatorExpression
: Expression 'AndAlso' LineTerminator? Expression
| Expression 'OrElse' LineTerminator? Expression
;
Vanwege hun kortsluitingsgedrag wordt de tweede operand niet geëvalueerd tijdens runtime als het resultaat van de operator bekend is na het evalueren van de eerste operand.
De logische operators voor kortsluiting worden als volgt geëvalueerd:
Als de eerste operand in een
AndAlsobewerking Waar oplevertFalseof retourneert vanuitIsFalsede operator, retourneert de expressie de eerste operand. Anders wordt de tweede operand geëvalueerd en wordt een logischeAndbewerking uitgevoerd op de twee resultaten.Als de eerste operand in een
OrElsebewerking Waar oplevertTrueof retourneert vanuitIsTruede operator, retourneert de expressie de eerste operand. Anders wordt de tweede operand geëvalueerd en wordt een logischeOrbewerking uitgevoerd op de twee resultaten.
De AndAlso operators en OrElse operators zijn gedefinieerd voor het type Booleanof voor elk type T dat de volgende operators overbelast:
Public Shared Operator IsTrue(op As T) As Boolean
Public Shared Operator IsFalse(op As T) As Boolean
en overbelasting van de corresponderende And of Or operator:
Public Shared Operator And(op1 As T, op2 As T) As T
Public Shared Operator Or(op1 As T, op2 As T) As T
Bij het evalueren van de AndAlso of OrElse operators wordt de eerste operand slechts één keer geëvalueerd en wordt de tweede operand niet exact één keer geëvalueerd of geëvalueerd. Denk bijvoorbeeld aan de volgende code:
Module Test
Function TrueValue() As Boolean
Console.Write(" True")
Return True
End Function
Function FalseValue() As Boolean
Console.Write(" False")
Return False
End Function
Sub Main()
Console.Write("And:")
If FalseValue() And TrueValue() Then
End If
Console.WriteLine()
Console.Write("Or:")
If TrueValue() Or FalseValue() Then
End If
Console.WriteLine()
Console.Write("AndAlso:")
If FalseValue() AndAlso TrueValue() Then
End If
Console.WriteLine()
Console.Write("OrElse:")
If TrueValue() OrElse FalseValue() Then
End If
Console.WriteLine()
End Sub
End Module
Het volgende resultaat wordt afgedrukt:
And: False True
Or: True False
AndAlso: False
OrElse: True
In de opgeheven vorm van de AndAlso en OrElse operators, als de eerste operand een null Boolean?was, wordt de tweede operand geëvalueerd, maar het resultaat is altijd een null Boolean?.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob |
| SB | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | |
| Bij | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | ||
| Sh | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | |||
| VS | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | ||||
| In | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | |||||
| ui- | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | ||||||
| Lo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | |||||||
| UL | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | ||||||||
| De | Bo | Bo | Bo | Err | Err | Bo | Ob | |||||||||
| Si | Bo | Bo | Err | Err | Bo | Ob | ||||||||||
| Doen | Bo | Err | Err | Bo | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| St | Bo | Ob | ||||||||||||||
| Ob | Ob |
Shift-operatoren
De binaire operatoren << en >> bitverschuifbewerkingen uitvoeren.
ShiftOperatorExpression
: Expression '<' '<' LineTerminator? Expression
| Expression '>' '>' LineTerminator? Expression
;
De operators worden gedefinieerd voor de Bytetypen , , SByte, UShortShort, UIntegeren ULongIntegerLong . In tegenstelling tot de andere binaire operatoren wordt het resultaattype van een dienstbewerking bepaald alsof de operator een unaire operator was met alleen de linkeroperand. Het type van de rechteroperand moet impliciet worden omgezet in Integer en wordt niet gebruikt bij het bepalen van het resultaattype van de bewerking.
De << operator zorgt ervoor dat de bits in de eerste operand worden verschoven naar links het aantal plaatsen dat is opgegeven door de verschuivingshoeveelheid. De bits met hoge volgorde buiten het bereik van het resultaattype worden verwijderd en de onbeschikde bitposities van lage volgorde zijn opgevuld.
De >> operator zorgt ervoor dat de bits in de eerste operand worden verschoven naar rechts het aantal plaatsen dat is opgegeven door de verschuivingshoeveelheid. De bits met lage volgorde worden verwijderd en de verwijderde bitposities in hoge volgorde worden ingesteld op nul als de linkeroperand positief is of op één als negatief. Als de linkeroperand van het typeByte, UShortUIntegerof ULong de lege high-order bits nul gevuld is.
De shiftoperators verschuiven de bits van de onderliggende weergave van de eerste operand op de hoeveelheid van de tweede operand. Als de waarde van de tweede operand groter is dan het aantal bits in de eerste operand of negatief is, wordt de verschuivingshoeveelheid berekend zoals RightOperand And SizeMask waar SizeMask is:
| LeftOperand Type | SizeMask |
|---|---|
Byte, SByte |
7 (&H7) |
UShort, Short |
15 (&HF) |
UInteger, Integer |
31 (&H1F) |
ULong, Long |
63 (&H3F) |
Als het verschuivingsbedrag nul is, is het resultaat van de bewerking identiek aan de waarde van de eerste operand. Er zijn geen overloopmogelijkheden bij deze bewerkingen.
Bewerkingstype:
| Bo | SB | Bij | Sh | VS | In | ui- | Lo | UL | De | Si | Doen | Da | Ch | St | Ob |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Sh | SB | Bij | Sh | VS | In | UI (Gebruikersinterface) | Lo | UL | Lo | Lo | Lo | Err | Err | Lo | Ob |
Booleaanse expressies
Een Boole-expressie is een expressie die kan worden getest om te zien of deze waar is of als deze onwaar is.
BooleanExpression
: Expression
;
Een type T kan worden gebruikt in een Boole-expressie als, in volgorde van voorkeur:
TisBooleanofBoolean?Theeft een brede conversie naarBooleanTheeft een brede conversie naarBoolean?Tdefinieert twee pseudooperators,IsTrueenIsFalse.Theeft een vermalingsconversie naarBoolean?die geen conversie vanBooleannaarBoolean?.Theeft een narrowing conversie naarBoolean.
Opmerking. Het is interessant om te weten dat als Option Strict deze is uitgeschakeld, een expressie met een beperkte conversie Boolean wordt geaccepteerd zonder een compilatiefout, maar de taal geeft nog steeds de voorkeur aan een IsTrue operator als deze bestaat. Dit komt doordat Option Strict alleen de betekenis van een expressie wordt gewijzigd en niet wordt geaccepteerd door de taal en nooit de werkelijke betekenis van een expressie wijzigt.
IsTrue Daarom moet altijd de voorkeur worden gegeven aan een smalle conversie, ongeachtOption Strict.
De volgende klasse definieert bijvoorbeeld geen widening conversie naar Boolean. Als gevolg hiervan veroorzaakt het gebruik in de If instructie een aanroep naar de IsTrue operator.
Class MyBool
Public Shared Widening Operator CType(b As Boolean) As MyBool
...
End Operator
Public Shared Narrowing Operator CType(b As MyBool) As Boolean
...
End Operator
Public Shared Operator IsTrue(b As MyBool) As Boolean
...
End Operator
Public Shared Operator IsFalse(b As MyBool) As Boolean
...
End Operator
End Class
Module Test
Sub Main()
Dim b As New MyBool
If b Then Console.WriteLine("True")
End Sub
End Module
Als een Boole-expressie is getypt als of wordt geconverteerd naar Boolean of Boolean?, is deze waar als de waarde en anders onwaar zijn True .
Anders roept een Boole-expressie de IsTrue operator aan en retourneert True deze als de operator is Truegeretourneerd; anders is deze onwaar (maar roept de operator nooit aan IsFalse ).
In het volgende voorbeeld Integer heeft een vermalende conversie naar Boolean, dus een null-conversie Integer? heeft een vermalende conversie naar zowel Boolean? (het opleveren van een null Boolean) als Boolean (waardoor een uitzondering wordt gegenereerd). De vermalingsconversie is Boolean? de voorkeur, dus de waarde van 'i' als een Boole-expressie is daarom False.
Dim i As Integer? = Nothing
If i Then Console.WriteLine()
Lambda-expressies
Een lambda-expressie definieert een anonieme methode die een lambda-methode wordt genoemd. Lambda-methoden maken het eenvoudig om 'inline'-methoden door te geven aan andere methoden die gedelegeerdentypen gebruiken.
LambdaExpression
: SingleLineLambda
| MultiLineLambda
;
SingleLineLambda
: LambdaModifier* 'Function' ( OpenParenthesis ParameterList? CloseParenthesis )? Expression
| 'Sub' ( OpenParenthesis ParameterList? CloseParenthesis )? Statement
;
MultiLineLambda
: MultiLineFunctionLambda
| MultiLineSubLambda
;
MultiLineFunctionLambda
: LambdaModifier? 'Function' ( OpenParenthesis ParameterList? CloseParenthesis )? ( 'As' TypeName )? LineTerminator
Block
'End' 'Function'
;
MultiLineSubLambda
: LambdaModifier? 'Sub' ( OpenParenthesis ParameterList? CloseParenthesis )? LineTerminator
Block
'End' 'Sub'
;
LambdaModifier
: 'Async' | 'Iterator'
;
Het voorbeeld:
Module Test
Delegate Function IntFunc(x As Integer) As Integer
Sub Apply(a() As Integer, func As IntFunc)
For index As Integer = 0 To a.Length - 1
a(index) = func(a(index))
Next index
End Sub
Sub Main()
Dim a() As Integer = { 1, 2, 3, 4 }
Apply(a, Function(x As Integer) x * 2)
For Each value In a
Console.Write(value & " ")
Next value
End Sub
End Module
wordt afgedrukt:
2 4 6 8
Een lambda-expressie begint met de optionele modifiers Async of Iterator, gevolgd door het trefwoord Function of Sub een parameterlijst. Parameters in een lambda-expressie kunnen niet worden gedeclareerd Optional of ParamArray kunnen geen kenmerken hebben. In tegenstelling tot reguliere methoden, leidt het weglaten van een parametertype voor een lambda-methode niet automatisch af Object. Wanneer een lambda-methode opnieuw wordt geclassificeerd, worden de weggelaten parametertypen en ByRef modifiers afgeleid van het doeltype. In het vorige voorbeeld zou de lambda-expressie kunnen zijn geschreven als Function(x) x * 2, en zou dit het type hebben afgeleid dat x moet zijn Integer wanneer de lambda-methode werd gebruikt om een exemplaar van het IntFunc type gemachtigde te maken. In tegenstelling tot lokale variabeledeductie, als een lambda-methodeparameter een type weglaat maar een matrix- of null-naamaanpassing heeft, treedt er een compilatietijdfout op.
Een reguliere lambda-expressie is een expressie met noch AsyncIterator modifiers.
Een iterator lambda-expressie is een expressie met de Iterator modifier en geen Async wijzigingsfunctie. Het moet een functie zijn. Wanneer deze opnieuw wordt geclassificeerd naar een waarde, kan deze alleen worden geclassificeerd naar een waarde van het gemachtigdetype waarvan het retourtype isIEnumerator, of IEnumerator(Of T)IEnumerableIEnumerable(Of T) voor sommigeT, en die geen ByRef-parameters heeft.
Een asynchrone lambda-expressie is een expressie met de Async modifier en geen Iterator wijzigingsfunctie. Een asynchrone sub lambda kan alleen opnieuw worden geclassificeerd naar een waarde van het type subdelegeer zonder ByRef-parameters. Een asynchrone functie lambda kan alleen opnieuw worden geclassificeerd naar een waarde van het type functiedelegen waarvan het retourtype is Task of Task(Of T) voor sommige T, en waarvoor geen ByRef-parameters zijn.
Lambda-expressies kunnen één regel of meerdere regels zijn. Lambda-expressies met één regel Function bevatten één expressie die de waarde vertegenwoordigt die wordt geretourneerd door de lambda-methode. Lambda-expressies met één regel Sub bevatten één instructie zonder dat deze wordt gesloten StatementTerminator. Voorbeeld:
Module Test
Sub Do(a() As Integer, action As Action(Of Integer))
For index As Integer = 0 To a.Length - 1
action(a(index))
Next index
End Sub
Sub Main()
Dim a() As Integer = { 1, 2, 3, 4 }
Do(a, Sub(x As Integer) Console.WriteLine(x))
End Sub
End Module
Lambda-constructies met één regel binden minder strak dan alle andere expressies en instructies. Zo is 'Function() x + 5' bijvoorbeeld gelijk aan 'Function() (x+5)" in plaats van '(Function() x) + 5'. Om dubbelzinnigheid te voorkomen, bevat een lambda-expressie met één regel Sub mogelijk geen Dim-instructie of een labeldeclaratie-instructie. Ook, tenzij deze tussen haakjes staat, kan een lambda-expressie met één regel Sub niet direct worden gevolgd door een dubbele punt ':', een operator voor lidtoegang '', een operator voor toegang tot woordenlijstleden '!' of een open haakje '(". Het mag geen blokinstructie (With, SyncLock, If...EndIf, While, For, , Do, ) Usingof OnError .Resume
Opmerking. In de lambda-expressie Function(i) x=iwordt de hoofdtekst geïnterpreteerd als een expressie (die test of x en i gelijk zijn). Maar in de lambda-expressie Sub(i) x=iwordt de hoofdtekst geïnterpreteerd als een instructie (die aan xtoewijsti).
Een lambda-expressie met meerdere regels bevat een instructieblok en moet eindigen met een geschikte End instructie (dat wil End Function zeggen of End Sub). Net als bij reguliere methoden moeten de of instructie en instructies van een lambda-methode Function met SubEnd meerdere regels op hun eigen regels staan. Voorbeeld:
' Error: Function statement must be on its own line!
Dim x = Sub(x As Integer) : Console.WriteLine(x) : End Sub
' OK
Dim y = Sub(x As Integer)
Console.WriteLine(x)
End Sub
Lambda-expressies met meerdere regels Function kunnen een retourtype declareren, maar kunnen er geen kenmerken op plaatsen. Als een lambda-expressie met meerdere regels Function geen retourtype declareert, maar het retourtype kan worden afgeleid uit de context waarin de lambda-expressie wordt gebruikt, wordt dat retourtype gebruikt. Anders wordt het retourtype van de functie als volgt berekend:
In een reguliere lambda-expressie is het retourtype het dominante type van de expressies in alle
Returninstructies in het instructieblok.In een asynchrone lambda-expressie is
Task(Of T)het retourtype waarThet dominante type expressies in alleReturninstructies in het instructieblok is.In een iterator lambda-expressie is
IEnumerable(Of T)het retourtype hetTdominante type van de expressies in alleYieldinstructies in het instructieblok.
Voorbeeld:
Function f(min As Integer, max As Integer) As IEnumerable(Of Integer)
If min > max Then Throw New ArgumentException()
Dim x = Iterator Function()
For i = min To max
Yield i
Next
End Function
' infers x to be a delegate with return type IEnumerable(Of Integer)
Return x()
End Function
In alle gevallen, als er geen Return (respectievelijk Yield) instructies zijn of als er geen dominant type is, en strikte semantiek wordt gebruikt, treedt er een compilatietijdfout op; anders is het dominante type impliciet Object.
Houd er rekening mee dat het retourtype wordt berekend op basis van alle Return instructies, zelfs als ze niet bereikbaar zijn. Voorbeeld:
' Return type is Double
Dim x = Function()
Return 10
Return 10.50
End Function
Er is geen impliciete retourvariabele, omdat er geen naam voor de variabele is.
De instructieblokken binnen lambda-expressies met meerdere regels hebben de volgende beperkingen:
On ErrorenResumeinstructies zijn niet toegestaan, hoewelTryinstructies zijn toegestaan.Statische lokale bevolking kan niet worden gedeclareerd in lambda-expressies met meerdere regels.
Het is niet mogelijk om het instructieblok van een lambda-expressie met meerdere regels te vertakken, hoewel de normale vertakkingsregels erin van toepassing zijn. Voorbeeld:
Label1: Dim x = Sub() ' Error: Cannot branch out GoTo Label1 ' OK: Wholly within the lamba. GoTo Label2: Label2: End Sub ' Error: Cannot branch in GoTo Label2
Een lambda-expressie is ongeveer gelijk aan een anonieme methode die is gedeclareerd op het type met daarin. Het eerste voorbeeld is ongeveer gelijk aan:
Module Test
Delegate Function IntFunc(x As Integer) As Integer
Sub Apply(a() As Integer, func As IntFunc)
For index As Integer = 0 To a.Length - 1
a(index) = func(a(index))
Next index
End Sub
Function $Lambda1(x As Integer) As Integer
Return x * 2
End Function
Sub Main()
Dim a() As Integer = { 1, 2, 3, 4 }
Apply(a, AddressOf $Lambda1)
For Each value In a
Console.Write(value & " ")
Next value
End Sub
End Module
Sluitingen
Lambda-expressies hebben toegang tot alle variabelen binnen het bereik, inclusief lokale variabelen of parameters die zijn gedefinieerd in de opgegeven methode en lambda-expressies. Wanneer een lambda-expressie verwijst naar een lokale variabele of parameter, legt de lambda-expressie de variabele vast waarnaar wordt verwezen in een sluiting. Een sluiting is een object dat zich op de heap bevindt in plaats van op de stapel en wanneer een variabele wordt vastgelegd, worden alle verwijzingen naar de variabele omgeleid naar de sluiting. Hierdoor kunnen lambda-expressies blijven verwijzen naar lokale variabelen en parameters, zelfs nadat de bijbehorende methode is voltooid. Voorbeeld:
Module Test
Delegate Function D() As Integer
Function M() As D
Dim x As Integer = 10
Return Function() x
End Function
Sub Main()
Dim y As D = M()
' Prints 10
Console.WriteLine(y())
End Sub
End Module
is ongeveer gelijk aan:
Module Test
Delegate Function D() As Integer
Class $Closure1
Public x As Integer
Function $Lambda1() As Integer
Return x
End Function
End Class
Function M() As D
Dim c As New $Closure1()
c.x = 10
Return AddressOf c.$Lambda1
End Function
Sub Main()
Dim y As D = M()
' Prints 10
Console.WriteLine(y())
End Sub
End Module
Een sluiting legt een nieuwe kopie van een lokale variabele vast telkens wanneer deze het blok invoert waarin de lokale variabele wordt gedeclareerd, maar de nieuwe kopie wordt geïnitialiseerd met de waarde van de vorige kopie, indien van toepassing. Voorbeeld:
Module Test
Delegate Function D() As Integer
Function M() As D()
Dim a(9) As D
For i As Integer = 0 To 9
Dim x
a(i) = Function() x
x += 1
Next i
Return a
End Function
Sub Main()
Dim y() As D = M()
For i As Integer = 0 To 9
Console.Write(y(i)() & " ")
Next i
End Sub
End Module
Afdrukken
1 2 3 4 5 6 7 8 9 10
In plaats van
9 9 9 9 9 9 9 9 9 9
Omdat sluitingen moeten worden geïnitialiseerd bij het invoeren van een blok, mag het niet GoTo in een blok met een sluiting van buiten dat blok, hoewel het is toegestaan om een blok met een sluiting in te Resume gaan. Voorbeeld:
Module Test
Sub Main()
Dim a = 10
If a = 10 Then
L1:
Dim x = Function() a
' Valid, source is within block
GoTo L2
L2:
End If
' ERROR: target is inside block with closure
GoTo L1
End Sub
End Module
Omdat ze niet kunnen worden vastgelegd in een sluiting, kan het volgende niet worden weergegeven in een lambda-expressie:
Referentieparameters.
Exemplaarexpressies (
Me,MyClass,MyBase), als het typeMegeen klasse is.
De leden van een anonieme expressie voor het maken van typen, als de lambda-expressie deel uitmaakt van de expressie. Voorbeeld:
' Error: Lambda cannot refer to anonymous type field
Dim x = New With { .a = 12, .b = Function() .a }
ReadOnly instantievariabelen in instantieconstructors of ReadOnly gedeelde variabelen in gedeelde constructors waarbij de variabelen worden gebruikt in een context zonder waarde. Voorbeeld:
Class C1
ReadOnly F1 As Integer
Sub New()
' Valid, doesn't modify F1
Dim x = Function() F1
' Error, tries to modify F1
Dim f = Function() ModifyValue(F1)
End Sub
Sub ModifyValue(ByRef x As Integer)
End Sub
End Class
Queryexpressies
Een query-expressie is een expressie waarmee een reeks queryoperators wordt toegepast op de elementen van een querybare verzameling. De volgende expressie gebruikt bijvoorbeeld een verzameling Customer objecten en retourneert de namen van alle klanten in de staat Washington:
Dim names = _
From cust In Customers _
Where cust.State = "WA" _
Select cust.Name
Een query-expressie moet beginnen met een From of een Aggregate operator en kan eindigen met elke queryoperator. Het resultaat van een query-expressie wordt geclassificeerd als een waarde; het resultaattype van de expressie is afhankelijk van het resultaattype van de laatste queryoperator in de expressie.
QueryExpression
: FromOrAggregateQueryOperator QueryOperator*
;
FromOrAggregateQueryOperator
: FromQueryOperator
| AggregateQueryOperator
;
QueryOperator
: FromQueryOperator
| AggregateQueryOperator
| SelectQueryOperator
| DistinctQueryOperator
| WhereQueryOperator
| OrderByQueryOperator
| PartitionQueryOperator
| LetQueryOperator
| GroupByQueryOperator
| JoinOrGroupJoinQueryOperator
;
JoinOrGroupJoinQueryOperator
: JoinQueryOperator
| GroupJoinQueryOperator
;
Bereikvariabelen
Sommige queryoperators introduceren een speciaal type variabele, een bereikvariabele genoemd. Bereikvariabelen zijn geen echte variabelen; In plaats daarvan vertegenwoordigen ze de afzonderlijke waarden tijdens de evaluatie van de query over de invoerverzamelingen.
CollectionRangeVariableDeclarationList
: CollectionRangeVariableDeclaration ( Comma CollectionRangeVariableDeclaration )*
;
CollectionRangeVariableDeclaration
: Identifier ( 'As' TypeName )? 'In' LineTerminator? Expression
;
ExpressionRangeVariableDeclarationList
: ExpressionRangeVariableDeclaration ( Comma ExpressionRangeVariableDeclaration )*
;
ExpressionRangeVariableDeclaration
: Identifier ( 'As' TypeName )? Equals Expression
;
Bereikvariabelen zijn gericht vanaf de introductiequeryoperator tot het einde van een query-expressie of tot een queryoperator, zoals Select die deze verbergt. Bijvoorbeeld in de volgende query
Dim waCusts = _
From cust As Customer In Customers _
Where cust.State = "WA"
de From queryoperator introduceert een bereikvariabele cust die is getypt als Customer die elke klant in de Customers verzameling vertegenwoordigt. De volgende Where queryoperator verwijst vervolgens naar de bereikvariabele cust in de filterexpressie om te bepalen of een afzonderlijke klant uit de resulterende verzameling moet filteren.
Er zijn twee typen bereikvariabelen: verzamelingsbereikvariabelen en expressiebereikvariabelen. Verzamelingsbereikvariabelen nemen hun waarden op uit de elementen van de verzamelingen waarop een query wordt uitgevoerd. De verzamelingsexpressie in een declaratie van een verzamelingsbereikvariabele moet worden geclassificeerd als een waarde waarvan het type een query kan uitvoeren. Als het type van een verzamelingsbereikvariabele wordt weggelaten, wordt dit afgeleid van het elementtype van de verzamelingsexpressie of Object als de verzamelingsexpressie geen elementtype heeft (dat wil bijvoorbeeld alleen een Cast methode definiëren). Als de verzamelingsexpressie niet kan worden opgevraagd (het elementtype van de verzameling kan niet worden afgeleid), wordt er een compilatiefout weergegeven.
Een variabele voor het expressiebereik is een bereikvariabele waarvan de waarde wordt berekend door een expressie in plaats van een verzameling. In het volgende voorbeeld introduceert de Select queryoperator een expressiebereikvariabele die is berekend cityState op basis van twee velden:
Dim cityStates = _
From cust As Customer In Customers _
Select cityState = cust.City & "," & cust.State _
Where cityState.Length() < 10
Een variabele voor een expressiebereik is niet vereist om te verwijzen naar een andere bereikvariabele, hoewel een dergelijke variabele mogelijk van dubieuze waarde is. De expressie die is toegewezen aan een expressiebereikvariabele moet worden geclassificeerd als een waarde en moet impliciet worden omgezet in het type bereikvariabele, indien opgegeven.
Alleen in een Let-operator kan een variabele voor het expressiebereik het type hebben opgegeven. In andere operators, of als het type niet is opgegeven, wordt deductie van het lokale variabeletype gebruikt om het type bereikvariabele te bepalen.
Een bereikvariabele moet voldoen aan de regels voor het declareren van lokale variabelen met betrekking tot schaduw. Een bereikvariabele kan dus de naam van een lokale variabele of parameter in de omsluitmethode of een andere bereikvariabele niet verbergen (tenzij de queryoperator specifiek alle huidige bereikvariabelen in het bereik verbergt).
Query's uitvoeren op typen
Query-expressies worden geïmplementeerd door de expressie te vertalen in aanroepen naar bekende methoden voor een verzamelingstype. Deze goed gedefinieerde methoden definiëren het elementtype van de opvraagbare verzameling en de resultaattypen van queryoperators die worden uitgevoerd op de verzameling. Elke queryoperator geeft de methode of methoden op waarin de queryoperator over het algemeen wordt vertaald, hoewel de specifieke vertaling afhankelijk is van de implementatie. De methoden worden gegeven in de specificatie met behulp van een algemene indeling die er als volgt uitziet:
Function Select(selector As Func(Of T, R)) As CR
Het volgende is van toepassing op de methoden:
De methode moet een exemplaar of uitbreidingslid van het verzamelingstype zijn en moet toegankelijk zijn.
De methode kan algemeen zijn, mits dit mogelijk is om alle typeargumenten af te stellen.
De methode kan overbelast zijn, in welk geval overbelastingsresolutie wordt gebruikt om de exacte methode te bepalen die moet worden gebruikt.
Een ander type gemachtigde kan worden gebruikt in plaats van het type gemachtigde
Func, mits het dezelfde handtekening heeft, inclusief het retourtype, als het overeenkomendeFunctype.Het type
System.Linq.Expressions.Expression(Of D)kan worden gebruikt in plaats van het type gemachtigdeFunc, mits ditDeen gemachtigdentype is met dezelfde handtekening, inclusief het retourtype, als het overeenkomendeFunctype.Het type
Tvertegenwoordigt het elementtype van de invoerverzameling. Alle methoden die zijn gedefinieerd door een verzamelingstype, moeten hetzelfde invoerelementtype hebben om een query uit te voeren voor het verzamelingstype.Het type
Svertegenwoordigt het elementtype van de tweede invoerverzameling in het geval van queryoperators die joins uitvoeren.Het type
Kvertegenwoordigt een sleuteltype in het geval van queryoperators met een set bereikvariabelen die fungeren als sleutels.Het type
Nvertegenwoordigt een type dat wordt gebruikt als een numeriek type (hoewel het nog steeds een door de gebruiker gedefinieerd type kan zijn en geen intrinsiek numeriek type).Het type
Bvertegenwoordigt een type dat kan worden gebruikt in een Boole-expressie.Het type
Rvertegenwoordigt het elementtype van de resultaatverzameling als de queryoperator een resultaatverzameling produceert.Ris afhankelijk van het aantal bereikvariabelen binnen het bereik aan de conclusie van de queryoperator. Als één bereikvariabele binnen het bereik valt, is ditRhet type bereikvariabele. In het voorbeeldDim custNames = From c In Customers Select c.Namehet resultaat van de query is een verzamelingstype met een elementtype.
StringAls meerdere bereikvariabelen binnen het bereik vallen, is ditReen anoniem type dat alle bereikvariabelen in het bereik alsKeyvelden bevat. In het voorbeeld:Dim custNames = From c In Customers, o In c.Orders Select Name = c.Name, ProductName = o.ProductNamehet resultaat van de query is een verzamelingstype met een elementtype van een anoniem type met een alleen-lezen eigenschap met de naam
Namevan het typeStringen een alleen-lezen eigenschap met de naamProductNamevan het typeString.Binnen een queryexpressie zijn anonieme typen die worden gegenereerd om bereikvariabelen te bevatten transparant, wat betekent dat bereikvariabelen altijd beschikbaar zijn zonder kwalificatie. In het vorige voorbeeld zijn de bereikvariabelen
cbijvoorbeeld toegankelijk zonderokwalificatie in deSelectqueryoperator, ook al was het elementtype van de invoerverzameling een anoniem type.Het type
CXvertegenwoordigt een verzamelingstype, niet noodzakelijkerwijs het invoerverzamelingstype, waarvan het elementtype een bepaald typeXis.
Een opvraagbaar verzamelingstype moet voldoen aan een van de volgende voorwaarden, in volgorde van voorkeur:
Er moet een conforme
Selectmethode worden gedefinieerd.Het moet een van de volgende methoden hebben
Function AsEnumerable() As CT Function AsQueryable() As CTdie kan worden aangeroepen om een opvraagbare verzameling te verkrijgen. Als beide methoden worden opgegeven,
AsQueryableheeft de voorkeur bovenAsEnumerable.Het moet een methode hebben
Function Cast(Of T)() As CTdie kan worden aangeroepen met het type bereikvariabele om een querybare verzameling te produceren.
Omdat het bepalen van het elementtype van een verzameling onafhankelijk van een werkelijke methodeaanroep plaatsvindt, kan de toepasbaarheid van specifieke methoden niet worden bepaald. Bij het bepalen van het elementtype van een verzameling als er exemplaarmethoden zijn die overeenkomen met bekende methoden, worden extensiemethoden die overeenkomen met bekende methoden genegeerd.
De vertaling van de queryoperator vindt plaats in de volgorde waarin de queryoperators in de expressie voorkomen. Het is niet nodig dat een verzamelingsobject alle methoden implementeert die nodig zijn voor alle queryoperators, hoewel elk verzamelingsobject ten minste ondersteuning moet bieden voor de Select queryoperator. Als een benodigde methode niet aanwezig is, treedt er een compilatietijdfout op. Bij het binden van bekende methodenamen worden niet-methoden genegeerd voor het doel van meerdere overnames in interfaces en extensiemethodebinding, hoewel schaduwsemantiek nog steeds van toepassing is. Voorbeeld:
Class Q1
Public Function [Select](selector As Func(Of Integer, Integer)) As Q1
End Function
End Class
Class Q2
Inherits Q1
Public [Select] As Integer
End Class
Module Test
Sub Main()
Dim qs As New Q2()
' Error: Q2.Select still hides Q1.Select
Dim zs = From q In qs Select q
End Sub
End Module
Standaardquery-indexeerfunctie
Elk opvraagbaar verzamelingstype waarvan het elementtype is T en nog geen standaardeigenschap heeft, wordt beschouwd als een standaardeigenschap van de volgende algemene vorm:
Public ReadOnly Default Property Item(index As Integer) As T
Get
Return Me.ElementAtOrDefault(index)
End Get
End Property
De standaardeigenschap kan alleen worden verwezen met behulp van de syntaxis van de standaardeigenschapstoegang; de standaardeigenschap kan niet worden verwezen op naam. Voorbeeld:
Dim customers As IEnumerable(Of Customer) = ...
Dim customerThree = customers(2)
' Error, no such property
Dim customerFour = customers.Item(4)
Als het verzamelingstype geen lid heeft ElementAtOrDefault , treedt er een compilatietijdfout op.
Uit queryoperator
De From queryoperator introduceert een verzamelingsbereikvariabele die de afzonderlijke leden van een verzameling vertegenwoordigt die moeten worden opgevraagd.
FromQueryOperator
: LineTerminator? 'From' LineTerminator? CollectionRangeVariableDeclarationList
;
Bijvoorbeeld de query-expressie:
From c As Customer In Customers ...
kan worden beschouwd als equivalent aan
For Each c As Customer In Customers
...
Next c
Wanneer een From queryoperator meerdere verzamelingsbereikvariabelen declareert of niet de eerste From queryoperator in de queryexpressie is, wordt elke nieuwe verzamelingsbereikvariabele gekoppeld aan de bestaande reeks bereikvariabelen. Het resultaat is dat de query wordt geëvalueerd via het crossproduct van alle elementen in de gekoppelde verzamelingen. Bijvoorbeeld de expressie:
From c In Customers _
From e In Employees _
...
kan worden beschouwd als gelijkwaardig aan:
For Each c In Customers
For Each e In Employees
...
Next e
Next c
en is precies gelijk aan:
From c In Customers, e In Employees ...
De bereikvariabelen die zijn geïntroduceerd in eerdere queryoperators, kunnen worden gebruikt in een latere From queryoperator. In de volgende query-expressie verwijst de tweede From queryoperator bijvoorbeeld naar de waarde van de eerste bereikvariabele:
From c As Customer In Customers _
From o As Order In c.Orders _
Select c.Name, o
Meerdere bereikvariabelen in een From queryoperator of meerdere From queryoperators worden alleen ondersteund als het verzamelingstype een of beide van de volgende methoden bevat:
Function SelectMany(selector As Func(Of T, CR)) As CR
Function SelectMany(selector As Func(Of T, CS), _
resultsSelector As Func(Of T, S, R)) As CR
De code
Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs, y In ys ...
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = _
xs.SelectMany( _
Function(x As Integer) ys, _
Function(x As Integer, y As Integer) New With {x, y})...
Opmerking.
From is geen gereserveerd woord.
JoinQuery-operator
De Join queryoperator voegt bestaande bereikvariabelen samen met een nieuwe verzamelingsbereikvariabele, waardoor één verzameling wordt geproduceerd waarvan de elementen zijn samengevoegd op basis van een gelijkheidsexpressie.
JoinQueryOperator
: LineTerminator? 'Join' LineTerminator? CollectionRangeVariableDeclaration
JoinOrGroupJoinQueryOperator? LineTerminator? 'On' LineTerminator? JoinConditionList
;
JoinConditionList
: JoinCondition ( 'And' LineTerminator? JoinCondition )*
;
JoinCondition
: Expression 'Equals' LineTerminator? Expression
;
Voorbeeld:
Dim customersAndOrders = _
From cust In Customers _
Join ord In Orders On cust.ID Equals ord.CustomerID
De gelijkheidsexpressie is beperkter dan een reguliere gelijkheidsexpressie:
Beide expressies moeten worden geclassificeerd als een waarde.
Beide expressies moeten verwijzen naar ten minste één bereikvariabele.
De bereikvariabele die is gedeclareerd in de operator joinquery, moet worden verwezen door een van de expressies en die expressie mag niet verwijzen naar andere bereikvariabelen.
Als de typen van de twee expressies niet exact hetzelfde type zijn, dan
Als de gelijkheidsoperator is gedefinieerd voor de twee typen, worden beide expressies impliciet converteerbaar naar de operator en niet
Object, dan converteren beide expressies naar dat type.Als er anders een dominant type is waarnaar beide expressies impliciet kunnen worden geconverteerd, converteert u beide expressies naar dat type.
Anders treedt er een compilatietijdfout op.
De expressies worden vergeleken met behulp van hashwaarden (bijvoorbeeld door aanroepen GetHashCode()) in plaats van gelijkheidsoperators te gebruiken voor efficiëntie. Een Join queryoperator kan meerdere joins of gelijkheidsvoorwaarden uitvoeren in dezelfde operator. Een Join queryoperator wordt alleen ondersteund als het verzamelingstype een methode bevat:
Function Join(inner As CS, _
outerSelector As Func(Of T, K), _
innerSelector As Func(Of S, K), _
resultSelector As Func(Of T, S, R)) As CR
De code
Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs _
Join y In ys On x Equals y _
...
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = _
xs.Join( _
ys, _
Function(x As Integer) x, _
Function(y As Integer) y, _
Function(x As Integer, y As Integer) New With {x, y})...
Opmerking.Join, On en Equals zijn geen gereserveerde woorden.
Queryoperator toestaan
De Let queryoperator introduceert een variabele voor het expressiebereik. Hiermee kunt u een tussenliggende waarde berekenen zodra deze meerdere keren wordt gebruikt in latere queryoperators.
LetQueryOperator
: LineTerminator? 'Let' LineTerminator? ExpressionRangeVariableDeclarationList
;
Voorbeeld:
Dim taxedPrices = _
From o In Orders _
Let tax = o.Price * 0.088 _
Where tax > 3.50 _
Select o.Price, tax, total = o.Price + tax
kan worden beschouwd als gelijkwaardig aan:
For Each o In Orders
Dim tax = o.Price * 0.088
...
Next o
Een Let queryoperator wordt alleen ondersteund als het verzamelingstype een methode bevat:
Function Select(selector As Func(Of T, R)) As CR
De code
Dim xs() As Integer = ...
Dim zs = From x In xs _
Let y = x * 10 _
...
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim zs = _
xs.Select(Function(x As Integer) New With {x, .y = x * 10})...
Queryoperator selecteren
De Select queryoperator is vergelijkbaar met de Let queryoperator omdat hiermee expressiebereikvariabelen worden geïntroduceerd. Een Select queryoperator verbergt echter de momenteel beschikbare bereikvariabelen in plaats van eraan toe te voegen. Bovendien wordt het type van een expressiebereikvariabele die door een Select queryoperator is geïntroduceerd, altijd afgeleid met behulp van regels voor deductie van lokale variabeletypen. Een expliciet type kan niet worden opgegeven en als er geen type kan worden afgeleid, treedt er een compilatiefout op.
SelectQueryOperator
: LineTerminator? 'Select' LineTerminator? ExpressionRangeVariableDeclarationList
;
Bijvoorbeeld in de query:
Dim smiths = _
From cust In Customers _
Select name = cust.name _
Where name.EndsWith("Smith")
de Where queryoperator heeft alleen toegang tot de name bereikvariabele die door de Select operator is geïntroduceerd. Als de Where operator had geprobeerd te verwijzen cust, zou er een compilatietijdfout zijn opgetreden.
In plaats van expliciet de namen van de bereikvariabelen op te geven, kan een Select queryoperator de namen van de bereikvariabelen afleiden met behulp van dezelfde regels als expressies voor het maken van anonieme typen objecten. Voorbeeld:
Dim custAndOrderNames = _
From cust In Customers, ord In cust.Orders _
Select cust.name, ord.ProductName _
Where name.EndsWith("Smith")
Als de naam van de bereikvariabele niet wordt opgegeven en een naam niet kan worden afgeleid, treedt er een compilatietijdfout op. Als de Select queryoperator slechts één expressie bevat, treedt er geen fout op als een naam voor die bereikvariabele niet kan worden afgeleid, maar de bereikvariabele naamloos is. Voorbeeld:
Dim custAndOrderNames = _
From cust In Customers, ord In cust.Orders _
Select cust.Name & " bought " & ord.ProductName _
Take 10
Als er sprake is van dubbelzinnigheid in een Select queryoperator tussen het toewijzen van een naam aan een bereikvariabele en een gelijkheidsexpressie, heeft de naamtoewijzing de voorkeur. Voorbeeld:
Dim badCustNames = _
From c In Customers _
Let name = "John Smith" _
Select name = c.Name ' Creates a range variable named "name"
Dim goodCustNames = _
From c In Customers _
Let name = "John Smith" _
Select match = (name = c.Name)
Elke expressie in de Select queryoperator moet worden geclassificeerd als een waarde. Een Select queryoperator wordt alleen ondersteund als het verzamelingstype een methode bevat:
Function Select(selector As Func(Of T, R)) As CR
De code
Dim xs() As Integer = ...
Dim zs = From x In xs _
Select x, y = x * 10 _
...
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim zs = _
xs.Select(Function(x As Integer) New With {x, .y = x * 10})...
Operator voor afzonderlijke query's
De Distinct queryoperator beperkt de waarden in een verzameling alleen tot waarden met afzonderlijke waarden, zoals wordt bepaald door het elementtype voor gelijkheid te vergelijken.
DistinctQueryOperator
: LineTerminator? 'Distinct' LineTerminator?
;
Bijvoorbeeld de query:
Dim distinctCustomerPrice = _
From cust In Customers, ord In cust.Orders _
Select cust.Name, ord.Price _
Distinct
retourneert slechts één rij voor elke afzonderlijke combinatie van klantnaam en orderprijs, zelfs als de klant meerdere orders met dezelfde prijs heeft. Een Distinct queryoperator wordt alleen ondersteund als het verzamelingstype een methode bevat:
Function Distinct() As CT
De code
Dim xs() As Integer = ...
Dim zs = From x In xs _
Distinct _
...
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim zs = xs.Distinct()...
Opmerking.
Distinct is geen gereserveerd woord.
Where Query Operator
De Where queryoperator beperkt de waarden in een verzameling tot de waarden die voldoen aan een bepaalde voorwaarde.
WhereQueryOperator
: LineTerminator? 'Where' LineTerminator? BooleanExpression
;
Een Where queryoperator gebruikt een Boole-expressie die wordt geëvalueerd voor elke set bereikvariabelewaarden. Als de waarde van de expressie waar is, worden de waarden weergegeven in de uitvoerverzameling, anders worden de waarden overgeslagen. Bijvoorbeeld de query-expressie:
From cust In Customers, ord In Orders _
Where cust.ID = ord.CustomerID _
...
kan worden beschouwd als gelijkwaardig aan de geneste lus
For Each cust In Customers
For Each ord In Orders
If cust.ID = ord.CustomerID Then
...
End If
Next ord
Next cust
Een Where queryoperator wordt alleen ondersteund als het verzamelingstype een methode bevat:
Function Where(predicate As Func(Of T, B)) As CT
De code
Dim xs() As Integer = ...
Dim zs = From x In xs _
Where x < 10 _
...
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim zs = _
xs.Where(Function(x As Integer) x < 10)...
Opmerking.
Where is geen gereserveerd woord.
Partitiequeryoperators
PartitionQueryOperator
: LineTerminator? 'Take' LineTerminator? Expression
| LineTerminator? 'Take' 'While' LineTerminator? BooleanExpression
| LineTerminator? 'Skip' LineTerminator? Expression
| LineTerminator? 'Skip' 'While' LineTerminator? BooleanExpression
;
De Take queryoperator resulteert in de eerste n elementen van een verzameling. Wanneer deze wordt gebruikt met de While modifier, resulteert de Take operator in de eerste n elementen van een verzameling die voldoen aan een Boole-expressie. De Skip operator slaat de eerste n elementen van een verzameling over en retourneert vervolgens de rest van de verzameling. Wanneer deze wordt gebruikt in combinatie met de While modifier, slaat de Skip operator de eerste n elementen van een verzameling over die voldoen aan een Boole-expressie en retourneert de rest van de verzameling. De expressies in een Take of Skip queryoperator moeten worden geclassificeerd als een waarde.
Een Take queryoperator wordt alleen ondersteund als het verzamelingstype een methode bevat:
Function Take(count As N) As CT
Een Skip queryoperator wordt alleen ondersteund als het verzamelingstype een methode bevat:
Function Skip(count As N) As CT
Een Take While queryoperator wordt alleen ondersteund als het verzamelingstype een methode bevat:
Function TakeWhile(predicate As Func(Of T, B)) As CT
Een Skip While queryoperator wordt alleen ondersteund als het verzamelingstype een methode bevat:
Function SkipWhile(predicate As Func(Of T, B)) As CT
De code
Dim xs() As Integer = ...
Dim zs = From x In xs _
Skip 10 _
Take 5 _
Skip While x < 10 _
Take While x > 5 _
...
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim zs = _
xs.Skip(10). _
Take(5). _
SkipWhile(Function(x) x < 10). _
TakeWhile(Function(x) x > 5)...
Opmerking.
Take en Skip zijn geen gereserveerde woorden.
Order By Query Operator
De Order By queryoperator bestelt de waarden die worden weergegeven in de bereikvariabelen.
OrderByQueryOperator
: LineTerminator? 'Order' 'By' LineTerminator? OrderExpressionList
;
OrderExpressionList
: OrderExpression ( Comma OrderExpression )*
;
OrderExpression
: Expression Ordering?
;
Ordering
: 'Ascending' | 'Descending'
;
Een Order By queryoperator gebruikt expressies die de sleutelwaarden opgeven die moeten worden gebruikt om de iteratievariabelen te ordenen. De volgende query retourneert bijvoorbeeld producten gesorteerd op prijs:
Dim productsByPrice = _
From p In Products _
Order By p.Price _
Select p.Name
Een volgorde kan worden gemarkeerd als Ascending, in welk geval kleinere waarden vóór grotere waarden komen of Descending, in welk geval grotere waarden vóór kleinere waarden komen. De standaardinstelling voor een bestelling als er geen is opgegeven.Ascending De volgende query retourneert bijvoorbeeld producten gesorteerd op prijs met het duurste product eerst:
Dim productsByPriceDesc = _
From p In Products _
Order By p.Price Descending _
Select p.Name
De Order By queryoperator kan meerdere expressies opgeven voor het ordenen, in welk geval de verzameling op een geneste manier wordt geordend. Met de volgende query worden klanten bijvoorbeeld gesorteerd op staat, vervolgens op plaats binnen elke staat en vervolgens op postcode binnen elke stad:
Dim customersByLocation = _
From c In Customers _
Order By c.State, c.City, c.ZIP _
Select c.Name, c.State, c.City, c.ZIP
De expressies in een Order By queryoperator moeten worden geclassificeerd als een waarde. Een Order By queryoperator wordt alleen ondersteund als het verzamelingstype een of beide van de volgende methoden bevat:
Function OrderBy(keySelector As Func(Of T, K)) As CT
Function OrderByDescending(keySelector As Func(Of T, K)) As CT
Het retourtype CT moet een geordende verzameling zijn. Een geordende verzameling is een verzamelingstype dat een of beide methoden bevat:
Function ThenBy(keySelector As Func(Of T, K)) As CT
Function ThenByDescending(keySelector As Func(Of T, K)) As CT
De code
Dim xs() As Integer = ...
Dim zs = From x In xs _
Order By x Ascending, x Mod 2 Descending _
...
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim zs = _
xs.OrderBy(Function(x) x).ThenByDescending(Function(x) x Mod 2)...
Opmerking. Omdat queryoperators gewoon syntaxis toewijzen aan methoden waarmee een bepaalde querybewerking wordt geïmplementeerd, wordt het behoud van de volgorde niet bepaald door de taal en wordt bepaald door de implementatie van de operator zelf. Dit is vergelijkbaar met door de gebruiker gedefinieerde operators omdat de implementatie om de opteloperator voor een door de gebruiker gedefinieerd numeriek type te overbelasten, mogelijk niets doet wat lijkt op een toevoeging. Om voorspelbaarheid te behouden, wordt het implementeren van iets dat niet overeenkomt met de verwachtingen van gebruikers niet aanbevolen.
Opmerking.
Order en By zijn geen gereserveerde woorden.
Groeperen op queryoperator
De Group By queryoperator groepeert de bereikvariabelen in het bereik op basis van een of meer expressies en produceert vervolgens nieuwe bereikvariabelen op basis van deze groeperingen.
GroupByQueryOperator
: LineTerminator? 'Group' ( LineTerminator? ExpressionRangeVariableDeclarationList )?
LineTerminator? 'By' LineTerminator? ExpressionRangeVariableDeclarationList
LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
;
De volgende query groepeert bijvoorbeeld alle klanten Stateop en berekent vervolgens het aantal en de gemiddelde leeftijd van elke groep:
Dim averageAges = _
From cust In Customers _
Group By cust.State _
Into Count(), Average(cust.Age)
De Group By queryoperator heeft drie componenten: de optionele Group component, de By component en de Into component. De Group component heeft dezelfde syntaxis en hetzelfde effect als een Select queryoperator, behalve dat deze alleen van invloed is op de bereikvariabelen die beschikbaar zijn in de Into component en niet op de By component. Voorbeeld:
Dim averageAges = _
From cust In Customers _
Group cust.Age By cust.State _
Into Count(), Average(Age)
De By component declareert expressiebereikvariabelen die worden gebruikt als sleutelwaarden in de groeperingsbewerking. Met Into de component kunnen expressiebereikvariabelen worden opgegeven waarmee aggregaties worden berekend over elk van de groepen die door de By component worden gevormd. Binnen de Into component kan alleen een expressie worden toegewezen aan een expressie die een methodeaanroep van een statistische functie is. Een statistische functie is een functie voor het verzamelingstype van de groep (die mogelijk niet noodzakelijkerwijs hetzelfde verzamelingstype van de oorspronkelijke verzameling is) dat eruitziet als een van de volgende methoden:
Function _name_() As _type_
Function _name_(selector As Func(Of T, R)) As R
Als een statistische functie een gedelegeerdeargument gebruikt, kan de aanroepexpressie een argumentexpressie hebben die moet worden geclassificeerd als een waarde. De argumentexpressie kan gebruikmaken van de bereikvariabelen die binnen het bereik vallen; binnen de aanroep van een statistische functie vertegenwoordigen deze bereikvariabelen de waarden in de groep die worden gevormd, niet alle waarden in de verzameling. In het oorspronkelijke voorbeeld in deze sectie berekent de Average functie bijvoorbeeld het gemiddelde van de leeftijden van de klanten per staat in plaats van voor alle klanten samen.
Alle verzamelingstypen worden beschouwd als de statistische functie Group die erop is gedefinieerd. Hiervoor zijn geen parameters nodig en wordt de groep gewoon geretourneerd. Andere standaard statistische functies die een verzamelingstype kan bieden, zijn:
Count en LongCount, waarmee het aantal elementen in de groep of het aantal elementen in de groep wordt geretourneerd die voldoen aan een Boole-expressie.
Count en LongCount worden alleen ondersteund als het verzamelingstype een van de methoden bevat:
Function Count() As N
Function Count(selector As Func(Of T, B)) As N
Function LongCount() As N
Function LongCount(selector As Func(Of T, B)) As N
Sum, waarmee de som van een expressie wordt geretourneerd voor alle elementen in de groep.
Sum wordt alleen ondersteund als het verzamelingstype een van de methoden bevat:
Function Sum() As N
Function Sum(selector As Func(Of T, N)) As N
Min die de minimumwaarde van een expressie retourneert voor alle elementen in de groep.
Min wordt alleen ondersteund als het verzamelingstype een van de methoden bevat:
Function Min() As N
Function Min(selector As Func(Of T, N)) As N
Max, waarmee de maximumwaarde van een expressie wordt geretourneerd voor alle elementen in de groep.
Max wordt alleen ondersteund als het verzamelingstype een van de methoden bevat:
Function Max() As N
Function Max(selector As Func(Of T, N)) As N
Average, waarmee het gemiddelde van een expressie wordt geretourneerd voor alle elementen in de groep.
Average wordt alleen ondersteund als het verzamelingstype een van de methoden bevat:
Function Average() As N
Function Average(selector As Func(Of T, N)) As N
Any, waarmee wordt bepaald of een groep leden bevat of dat een Boole-expressie waar is voor een element in de groep.
Any retourneert een waarde die kan worden gebruikt in een Boole-expressie en wordt alleen ondersteund als het verzamelingstype een van de methoden bevat:
Function Any() As B
Function Any(predicate As Func(Of T, B)) As B
All, waarmee wordt bepaald of een Boole-expressie waar is voor alle elementen in de groep.
All retourneert een waarde die kan worden gebruikt in een Boole-expressie en wordt alleen ondersteund als het verzamelingstype een methode bevat:
Function All(predicate As Func(Of T, B)) As B
Na een Group By queryoperator zijn de bereikvariabelen die eerder binnen het bereik vallen verborgen en zijn de bereikvariabelen die door de By en Into componenten zijn geïntroduceerd, beschikbaar. Een Group By queryoperator wordt alleen ondersteund als het verzamelingstype de methode bevat:
Function GroupBy(keySelector As Func(Of T, K), _
resultSelector As Func(Of K, CT, R)) As CR
Declaraties van bereikvariabelen in de Group component worden alleen ondersteund als het verzamelingstype de methode bevat:
Function GroupBy(keySelector As Func(Of T, K), _
elementSelector As Func(Of T, S), _
resultSelector As Func(Of K, CS, R)) As CR
De code
Dim xs() As Integer = ...
Dim zs = From x In xs _
Group y = x * 10, z = x / 10 By evenOdd = x Mod 2 _
Into Sum(y), Average(z) _
...
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim zs = _
xs.GroupBy( _
Function(x As Integer) x Mod 2, _
Function(x As Integer) New With {.y = x * 10, .z = x / 10}, _
Function(evenOdd, group) New With { _
evenOdd, _
.Sum = group.Sum(Function(e) e.y), _
.Average = group.Average(Function(e) e.z)})...
Opmerking.Group, Byen Into zijn geen gereserveerde woorden.
Operator voor statistische query's
De Aggregate queryoperator voert een vergelijkbare functie uit als de Group By operator, met uitzondering van het samenvoegen van groepen die al zijn gevormd. Omdat de groep al is gevormd, verbergt de Into component van een Aggregate queryoperator de bereikvariabelen niet (op deze manier Aggregate lijkt het meer op een Leten Group By meer op een Select).
AggregateQueryOperator
: LineTerminator? 'Aggregate' LineTerminator? CollectionRangeVariableDeclaration QueryOperator*
LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
;
Met de volgende query wordt bijvoorbeeld het totaal samengevoegd van alle orders die zijn geplaatst door klanten in Washington:
Dim orderTotals = _
From cust In Customers _
Where cust.State = "WA" _
Aggregate order In cust.Orders _
Into Sum(order.Total)
Het resultaat van deze query is een verzameling waarvan het elementtype een anoniem type is met een eigenschap die cust is getypt als Customer en een eigenschap die Sum is getypt als Integer.
In tegenstelling tot Group By, kunnen extra queryoperators tussen de Aggregate en Into componenten worden geplaatst. Tussen een Aggregate component en het einde van de Into component kunnen alle bereikvariabelen in het bereik, inclusief de variabelen die door de Aggregate component zijn gedeclareerd, worden gebruikt. Met de volgende query wordt bijvoorbeeld het totaal samengevoegd van alle orders die vóór 2006 door klanten in Washington zijn geplaatst:
Dim orderTotals = _
From cust In Customers _
Where cust.State = "WA" _
Aggregate order In cust.Orders _
Where order.Date <= #01/01/2006# _
Into Sum = Sum(order.Total)
De Aggregate operator kan ook worden gebruikt om een query-expressie te starten. In dit geval is het resultaat van de query-expressie de enkele waarde die door de Into component wordt berekend. Met de volgende query wordt bijvoorbeeld de som berekend van alle ordertotalen vóór 1 januari 2006:
Dim ordersTotal = _
Aggregate order In Orders _
Where order.Date <= #01/01/2006# _
Into Sum(order.Total)
Het resultaat van de query is één Integer waarde. Een Aggregate queryoperator is altijd beschikbaar (hoewel de statistische functie ook beschikbaar moet zijn om de expressie geldig te kunnen maken). De code
Dim xs() As Integer = ...
Dim zs = _
Aggregate x In xs _
Where x < 5 _
Into Sum()
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim zs = _
xs.Where(Function(x) x < 5).Sum()
Opmerking.
Aggregate en Into zijn geen gereserveerde woorden.
Queryoperator Voor groepdeelname
De Group Join queryoperator combineert de functies van de Join operators en Group By query's in één operator.
Group Join voegt twee verzamelingen samen op basis van overeenkomende sleutels die zijn geëxtraheerd uit de elementen, waarbij alle elementen aan de rechterkant van de join worden gegroepeerd die overeenkomen met een bepaald element aan de linkerkant van de join. De operator produceert dus een set hiërarchische resultaten.
GroupJoinQueryOperator
: LineTerminator? 'Group' 'Join' LineTerminator? CollectionRangeVariableDeclaration
JoinOrGroupJoinQueryOperator? LineTerminator? 'On' LineTerminator? JoinConditionList
LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
;
De volgende query produceert bijvoorbeeld elementen die de naam van één klant bevatten, een groep van alle orders en het totale aantal orders:
Dim custsWithOrders = _
From cust In Customers _
Group Join order In Orders On cust.ID Equals order.CustomerID _
Into Orders = Group, OrdersTotal = Sum(order.Total) _
Select cust.Name, Orders, OrdersTotal
Het resultaat van de query is een verzameling waarvan het elementtype een anoniem type is met drie eigenschappen: Name, getypt als String, Orders getypt als een verzameling waarvan het elementtype is Orderen OrdersTotal, getypt als Integer. Een Group Join queryoperator wordt alleen ondersteund als het verzamelingstype de methode bevat:
Function GroupJoin(inner As CS, _
outerSelector As Func(Of T, K), _
innerSelector As Func(Of S, K), _
resultSelector As Func(Of T, CS, R)) As CR
De code
Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs _
Group Join y in ys On x Equals y _
Into g = Group _
...
wordt over het algemeen vertaald naar
Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = _
xs.GroupJoin( _
ys, _
Function(x As Integer) x, _
Function(y As Integer) y, _
Function(x, group) New With {x, .g = group})...
Opmerking.Group, Joinen Into zijn geen gereserveerde woorden.
Voorwaardelijke expressies
Een voorwaardelijke If expressie test een expressie en retourneert een waarde.
ConditionalExpression
: 'If' OpenParenthesis BooleanExpression Comma Expression Comma Expression CloseParenthesis
| 'If' OpenParenthesis Expression Comma Expression CloseParenthesis
;
In tegenstelling tot de IIF runtime-functie evalueert een voorwaardelijke expressie de operanden alleen indien nodig. De expressie If(c Is Nothing, c.Name, "Unknown") genereert dus bijvoorbeeld geen uitzondering als de waarde c is Nothing. De voorwaardelijke expressie heeft twee vormen: één met twee operanden en één die drie operanden gebruikt.
Als er drie operanden worden opgegeven, moeten alle drie de expressies worden geclassificeerd als waarden en moet de eerste operand een Boole-expressie zijn. Als het resultaat van de expressie waar is, is de tweede expressie het resultaat van de operator, anders is de derde expressie het resultaat van de operator. Het resultaattype van de expressie is het dominante type tussen de typen van de tweede en derde expressie. Als er geen dominant type is, treedt er een compilatietijdfout op.
Als er twee operanden worden opgegeven, moeten beide operanden worden geclassificeerd als waarden en moet de eerste operand een verwijzingstype of een null-waardetype zijn. De expressie If(x, y) wordt vervolgens geëvalueerd alsof het de expressie If(x IsNot Nothing, x, y)was, met twee uitzonderingen. Ten eerste wordt de eerste expressie slechts eenmaal geëvalueerd en ten tweede, als het type van de tweede operand een niet-null-waardetype is en het type van de eerste operand is, wordt het ? verwijderd uit het type van de eerste operand bij het bepalen van het dominante type voor het resultaattype van de expressie. Voorbeeld:
Module Test
Sub Main()
Dim x?, y As Integer
Dim a?, b As Long
a = If(x, a) ' Result type: Long?
y = If(x, 0) ' Result type: Integer
End Sub
End Module
In beide vormen van de expressie, als een operand is Nothing, wordt het type ervan niet gebruikt om het dominante type te bepalen. In het geval van de expressie If(<expression>, Nothing, Nothing)wordt het dominante type beschouwd als Object.
Letterlijke XML-expressies
Een letterlijke XML-expressie vertegenwoordigt een XML-waarde (eXtensible Markup Language) 1,0.
XMLLiteralExpression
: XMLDocument
| XMLElement
| XMLProcessingInstruction
| XMLComment
| XMLCDATASection
;
Het resultaat van een letterlijke XML-expressie is een waarde die is getypt als een van de typen uit de System.Xml.Linq naamruimte. Als de typen in die naamruimte niet beschikbaar zijn, veroorzaakt een letterlijke XML-expressie een compilatiefout. De waarden worden gegenereerd via constructor-aanroepen die zijn vertaald vanuit de letterlijke XML-expressie. Bijvoorbeeld de code:
Dim book As System.Xml.Linq.XElement = _
<book title="My book"></book>
is ongeveer gelijk aan de code:
Dim book As System.Xml.Linq.XElement = _
New System.Xml.Linq.XElement( _
"book", _
New System.Xml.Linq.XAttribute("title", "My book"))
Een letterlijke XML-expressie kan de vorm aannemen van een XML-document, een XML-element, een XML-verwerkingsinstructie, een XML-opmerking of een CDATA-sectie.
Opmerking. Deze specificatie bevat slechts voldoende beschrijving van XML om het gedrag van de Visual Basic-taal te beschrijven. Meer informatie over XML vindt u op http://www.w3.org/TR/REC-xml/.
Lexicale regels
XMLCharacter
: '<Unicode tab character (0x0009)>'
| '<Unicode linefeed character (0x000A)>'
| '<Unicode carriage return character (0x000D)>'
| '<Unicode characters 0x0020 - 0xD7FF>'
| '<Unicode characters 0xE000 - 0xFFFD>'
| '<Unicode characters 0x10000 - 0x10FFFF>'
;
XMLString
: XMLCharacter+
;
XMLWhitespace
: XMLWhitespaceCharacter+
;
XMLWhitespaceCharacter
: '<Unicode carriage return character (0x000D)>'
| '<Unicode linefeed character (0x000A)>'
| '<Unicode space character (0x0020)>'
| '<Unicode tab character (0x0009)>'
;
XMLNameCharacter
: XMLLetter
| XMLDigit
| '.'
| '-'
| '_'
| ':'
| XMLCombiningCharacter
| XMLExtender
;
XMLNameStartCharacter
: XMLLetter
| '_'
| ':'
;
XMLName
: XMLNameStartCharacter XMLNameCharacter*
;
XMLLetter
: '<Unicode character as defined in the Letter production of the XML 1.0 specification>'
;
XMLDigit
: '<Unicode character as defined in the Digit production of the XML 1.0 specification>'
;
XMLCombiningCharacter
: '<Unicode character as defined in the CombiningChar production of the XML 1.0 specification>'
;
XMLExtender
: '<Unicode character as defined in the Extender production of the XML 1.0 specification>'
;
Letterlijke XML-expressies worden geïnterpreteerd met behulp van de lexicale regels van XML in plaats van de lexicale regels van reguliere Visual Basic-code. De twee regelsets verschillen in het algemeen op de volgende manieren:
Witruimte is belangrijk in XML. Als gevolg hiervan geeft de grammatica voor letterlijke XML-expressies expliciet aan waar witruimte is toegestaan. Witruimte blijft niet behouden, behalve wanneer deze plaatsvindt in de context van tekengegevens binnen een element. Voorbeeld:
' The following element preserves no whitespace Dim e1 = _ <customer> <name>Bob</> </> ' The following element preserves all of the whitespace Dim e2 = _ <customer> Bob </>Xml-witruimte aan het einde van de regel wordt genormaliseerd volgens de XML-specificatie.
XML is hoofdlettergevoelig. Trefwoorden moeten exact overeenkomen met hoofdletters, anders treedt er een compilatietijdfout op.
Regeleindtekens worden beschouwd als witruimte in XML. Als gevolg hiervan zijn er geen regelvervolgtekens nodig in letterlijke XML-expressies.
XML accepteert geen tekens in volledige breedte. Als tekens met volledige breedte worden gebruikt, treedt er een compilatietijdfout op.
Ingesloten expressies
Letterlijke XML-expressies kunnen ingesloten expressies bevatten. Een ingesloten expressie is een Visual Basic-expressie die wordt geëvalueerd en wordt gebruikt om een of meer waarden in te vullen op de locatie van de ingesloten expressie.
XMLEmbeddedExpression
: '<' '%' '=' LineTerminator? Expression LineTerminator? '%' '>'
;
De volgende code plaatst de tekenreeks John Smith bijvoorbeeld als de waarde van het XML-element:
Dim name as String = "John Smith"
Dim element As System.Xml.Linq.XElement = <customer><%= name %></customer>
Expressies kunnen worden ingesloten in een aantal contexten. De volgende code produceert bijvoorbeeld een element met de naam customer:
Dim name As String = "customer"
Dim element As System.Xml.Linq.XElement = <<%= name %>>John Smith</>
Elke context waarin een ingesloten expressie kan worden gebruikt, geeft de typen op die worden geaccepteerd. Wanneer binnen de context van het expressiegedeelte van een ingesloten expressie de normale lexicale regels voor Visual Basic-code nog steeds van toepassing zijn, moeten bijvoorbeeld regelvervolgingen worden gebruikt:
' Visual Basic expression uses line continuation, XML does not
Dim element As System.Xml.Linq.XElement = _
<<%= name & _
name %>>John
Smith</>
XML-documenten
XMLDocument
: XMLDocumentPrologue XMLMisc* XMLDocumentBody XMLMisc*
;
XMLDocumentPrologue
: '<' '?' 'xml' XMLVersion XMLEncoding? XMLStandalone? XMLWhitespace? '?' '>'
;
XMLVersion
: XMLWhitespace 'version' XMLWhitespace? '=' XMLWhitespace? XMLVersionNumberValue
;
XMLVersionNumberValue
: SingleQuoteCharacter '1' '.' '0' SingleQuoteCharacter
| DoubleQuoteCharacter '1' '.' '0' DoubleQuoteCharacter
;
XMLEncoding
: XMLWhitespace 'encoding' XMLWhitespace? '=' XMLWhitespace? XMLEncodingNameValue
;
XMLEncodingNameValue
: SingleQuoteCharacter XMLEncodingName SingleQuoteCharacter
| DoubleQuoteCharacter XMLEncodingName DoubleQuoteCharacter
;
XMLEncodingName
: XMLLatinAlphaCharacter XMLEncodingNameCharacter*
;
XMLEncodingNameCharacter
: XMLUnderscoreCharacter
| XMLLatinAlphaCharacter
| XMLNumericCharacter
| XMLPeriodCharacter
| XMLDashCharacter
;
XMLLatinAlphaCharacter
: '<Unicode Latin alphabetic character (0x0041-0x005a, 0x0061-0x007a)>'
;
XMLNumericCharacter
: '<Unicode digit character (0x0030-0x0039)>'
;
XMLHexNumericCharacter
: XMLNumericCharacter
| '<Unicode Latin hex alphabetic character (0x0041-0x0046, 0x0061-0x0066)>'
;
XMLPeriodCharacter
: '<Unicode period character (0x002e)>'
;
XMLUnderscoreCharacter
: '<Unicode underscore character (0x005f)>'
;
XMLDashCharacter
: '<Unicode dash character (0x002d)>'
;
XMLStandalone
: XMLWhitespace 'standalone' XMLWhitespace? '=' XMLWhitespace? XMLYesNoValue
;
XMLYesNoValue
: SingleQuoteCharacter XMLYesNo SingleQuoteCharacter
| DoubleQuoteCharacter XMLYesNo DoubleQuoteCharacter
;
XMLYesNo
: 'yes'
| 'no'
;
XMLMisc
: XMLComment
| XMLProcessingInstruction
| XMLWhitespace
;
XMLDocumentBody
: XMLElement
| XMLEmbeddedExpression
;
Een XML-document resulteert in een waarde die is getypt als System.Xml.Linq.XDocument. In tegenstelling tot de XML 1.0-specificatie zijn XML-documenten in letterlijke XML-expressies vereist om de XML-documentproloog op te geven; Letterlijke XML-expressies zonder de XML-documentproloog worden geïnterpreteerd als hun afzonderlijke entiteit. Voorbeeld:
Dim doc As System.Xml.Linq.XDocument = _
<?xml version="1.0"?>
<?instruction?>
<customer>Bob</>
Dim pi As System.Xml.Linq.XProcessingInstruction = _
<?instruction?>
Een XML-document kan een ingesloten expressie bevatten waarvan het type elk type kan zijn; tijdens runtime moet het object echter voldoen aan de vereisten van de XDocument constructor of treedt er een runtimefout op.
In tegenstelling tot reguliere XML bieden XML-documentexpressies geen ondersteuning voor DTD's (Declaraties van documenttypen). Het coderingskenmerk, indien opgegeven, wordt ook genegeerd omdat de codering van de letterlijke XML-expressie altijd hetzelfde is als de codering van het bronbestand zelf.
Opmerking. Hoewel het coderingskenmerk wordt genegeerd, is het nog steeds een geldig kenmerk om de mogelijkheid te behouden om geldige Xml 1.0-documenten in broncode op te nemen.
XML-elementen
XMLElement
: XMLEmptyElement
| XMLElementStart XMLContent XMLElementEnd
;
XMLEmptyElement
: '<' XMLQualifiedNameOrExpression XMLAttribute* XMLWhitespace? '/' '>'
;
XMLElementStart
: '<' XMLQualifiedNameOrExpression XMLAttribute* XMLWhitespace? '>'
;
XMLElementEnd
: '<' '/' '>'
| '<' '/' XMLQualifiedName XMLWhitespace? '>'
;
XMLContent
: XMLCharacterData? ( XMLNestedContent XMLCharacterData? )+
;
XMLCharacterData
: '<Any XMLCharacterDataString that does not contain the string "]]>">'
;
XMLCharacterDataString
: '<Any Unicode character except < or &>'+
;
XMLNestedContent
: XMLElement
| XMLReference
| XMLCDATASection
| XMLProcessingInstruction
| XMLComment
| XMLEmbeddedExpression
;
XMLAttribute
: XMLWhitespace XMLAttributeName XMLWhitespace? '=' XMLWhitespace? XMLAttributeValue
| XMLWhitespace XMLEmbeddedExpression
;
XMLAttributeName
: XMLQualifiedNameOrExpression
| XMLNamespaceAttributeName
;
XMLAttributeValue
: DoubleQuoteCharacter XMLAttributeDoubleQuoteValueCharacter* DoubleQuoteCharacter
| SingleQuoteCharacter XMLAttributeSingleQuoteValueCharacter* SingleQuoteCharacter
| XMLEmbeddedExpression
;
XMLAttributeDoubleQuoteValueCharacter
: '<Any XMLCharacter except <, &, or DoubleQuoteCharacter>'
| XMLReference
;
XMLAttributeSingleQuoteValueCharacter
: '<Any XMLCharacter except <, &, or SingleQuoteCharacter>'
| XMLReference
;
XMLReference
: XMLEntityReference
| XMLCharacterReference
;
XMLEntityReference
: '&' XMLEntityName ';'
;
XMLEntityName
: 'lt' | 'gt' | 'amp' | 'apos' | 'quot'
;
XMLCharacterReference
: '&' '#' XMLNumericCharacter+ ';'
| '&' '#' 'x' XMLHexNumericCharacter+ ';'
;
Een XML-element resulteert in een waarde die is getypt als System.Xml.Linq.XElement. In tegenstelling tot gewone XML kunnen XML-elementen de naam weglaten in de afsluitende tag en wordt het meest geneste element gesloten. Voorbeeld:
Dim name = <name>Bob</>
Kenmerkdeclaraties in een XML-element resulteren in waarden die zijn getypt als System.Xml.Linq.XAttribute. Kenmerkwaarden worden genormaliseerd volgens de XML-specificatie. Wanneer de waarde van een kenmerk is Nothing , wordt het kenmerk niet gemaakt, zodat de expressie van de kenmerkwaarde niet hoeft te worden gecontroleerd Nothingop . Voorbeeld:
Dim expr = Nothing
' Throws null argument exception
Dim direct = New System.Xml.Linq.XElement( _
"Name", _
New System.Xml.Linq.XAttribute("Length", expr))
' Doesn't throw exception, the result is <Name/>
Dim literal = <Name Length=<%= expr %>/>
XML-elementen en -kenmerken kunnen geneste expressies bevatten op de volgende plaatsen:
De naam van het element, in welk geval de ingesloten expressie een waarde moet zijn van een type impliciet converteerbaar naar System.Xml.Linq.XName. Voorbeeld:
Dim name = <<%= "name" %>>Bob</>
De naam van een kenmerk van het element, in welk geval de ingesloten expressie een waarde moet zijn van een type impliciet converteerbaar naar System.Xml.Linq.XName. Voorbeeld:
Dim name = <name <%= "length" %>="3">Bob</>
De waarde van een kenmerk van het element, in welk geval de ingesloten expressie een waarde van elk type kan zijn. Voorbeeld:
Dim name = <name length=<%= 3 %>>Bob</>
Een kenmerk van het element, in welk geval de ingesloten expressie een waarde van elk type kan zijn. Voorbeeld:
Dim name = <name <%= new XAttribute("length", 3) %>>Bob</>
De inhoud van het element, in welk geval de ingesloten expressie een waarde van elk type kan zijn. Voorbeeld:
Dim name = <name><%= "Bob" %></>
Als het type van de ingesloten expressie is Object(), wordt de matrix doorgegeven als een paramarray aan de XElement constructor.
XML-naamruimten
XML-elementen kunnen declaraties van XML-naamruimten bevatten, zoals gedefinieerd door de XML-naamruimten 1.0-specificatie.
XMLNamespaceAttributeName
: XMLPrefixedNamespaceAttributeName
| XMLDefaultNamespaceAttributeName
;
XMLPrefixedNamespaceAttributeName
: 'xmlns' ':' XMLNamespaceName
;
XMLDefaultNamespaceAttributeName
: 'xmlns'
;
XMLNamespaceName
: XMLNamespaceNameStartCharacter XMLNamespaceNameCharacter*
;
XMLNamespaceNameStartCharacter
: '<Any XMLNameCharacter except :>'
;
XMLNamespaceNameCharacter
: XMLLetter
| '_'
;
XMLQualifiedNameOrExpression
: XMLQualifiedName
| XMLEmbeddedExpression
;
XMLQualifiedName
: XMLPrefixedName
| XMLUnprefixedName
;
XMLPrefixedName
: XMLNamespaceName ':' XMLNamespaceName
;
XMLUnprefixedName
: XMLNamespaceName
;
De beperkingen voor het definiëren van de naamruimten xml en xmlns worden afgedwongen en produceren compileertijdfouten. Declaraties van XML-naamruimten kunnen geen ingesloten expressie hebben voor hun waarde; de opgegeven waarde moet een letterlijke tekenreeks zijn die niet leeg is. Voorbeeld:
' Declares a valid namespace
Dim customer = <db:customer xmlns:db="http://example.org/database">Bob</>
' Error: xmlns cannot be re-defined
Dim bad1 = <elem xmlns:xmlns="http://example.org/namespace"/>
' Error: cannot have an embedded expression
Dim bad2 = <elem xmlns:db=<%= "http://example.org/database" %>>Bob</>
Opmerking. Deze specificatie bevat slechts voldoende beschrijving van een XML-naamruimte om het gedrag van de Visual Basic-taal te beschrijven. Meer informatie over XML-naamruimten vindt u op http://www.w3.org/TR/REC-xml-names/.
XML-element- en kenmerknamen kunnen worden gekwalificeerd met behulp van naamruimtenamen. Naamruimten zijn gebonden zoals in gewone XML, met uitzondering dat alle naamruimteimporten die zijn gedeclareerd op bestandsniveau, worden beschouwd als gedeclareerd in een context waarin de declaratie wordt geplaatst, die zelf wordt ingesloten door eventuele naamruimteimporten die door de compilatieomgeving worden gedeclareerd. Als een naamruimtenaam niet kan worden gevonden, treedt er een compilatietijdfout op. Voorbeeld:
Imports System.Xml.Linq
Imports <xmlns:db="http://example.org/database">
Module Test
Sub Main()
' Binds to the imported namespace above.
Dim c1 = <db:customer>Bob</>
' Binds to the namespace declaration in the element
Dim c2 = _
<db:customer xmlns:db="http://example.org/database-other">Mary</>
' Binds to the inner namespace declaration
Dim c3 = _
<database xmlns:db="http://example.org/database-one">
<db:customer xmlns:db="http://example.org/database-two">Joe</>
</>
' Error: namespace db2 cannot be found
Dim c4 = _
<db2:customer>Jim</>
End Sub
End Module
XML-naamruimten die in een element zijn gedeclareerd, zijn niet van toepassing op LETTERLIJKE XML-gegevens in ingesloten expressies. Voorbeeld:
' Error: Namespace prefix 'db' is not declared
Dim customer = _
<db:customer xmlns:db="http://example.org/database">
<%= <db:customer>Bob</> %>
</>
Opmerking. Dit komt doordat de ingesloten expressie alles kan zijn, inclusief een functie-aanroep. Als de functieaanroep een letterlijke XML-expressie bevat, is het niet duidelijk of programmeurs verwachten dat de XML-naamruimte wordt toegepast of genegeerd.
INSTRUCTIES voor XML-verwerking
Een XML-verwerkingsinstructie resulteert in een waarde die is getypt als System.Xml.Linq.XProcessingInstruction. XML-verwerkingsinstructies kunnen geen ingesloten expressies bevatten, omdat ze geldige syntaxis zijn binnen de verwerkingsinstructie.
XMLProcessingInstruction
: '<' '?' XMLProcessingTarget ( XMLWhitespace XMLProcessingValue? )? '?' '>'
;
XMLProcessingTarget
: '<Any XMLName except a casing permutation of the string "xml">'
;
XMLProcessingValue
: '<Any XMLString that does not contain a question-mark followed by ">">'
;
XML-opmerkingen
Een XML-opmerking resulteert in een waarde die is getypt als System.Xml.Linq.XComment. XML-opmerkingen kunnen geen ingesloten expressies bevatten, omdat ze geldige syntaxis in de opmerking zijn.
XMLComment
: '<' '!' '-' '-' XMLCommentCharacter* '-' '-' '>'
;
XMLCommentCharacter
: '<Any XMLCharacter except dash (0x002D)>'
| '-' '<Any XMLCharacter except dash (0x002D)>'
;
CDATA-secties
Een CDATA-sectie resulteert in een waarde die is getypt als System.Xml.Linq.XCData. CDATA-secties kunnen geen ingesloten expressies bevatten, omdat ze geldige syntaxis zijn binnen de CDATA-sectie.
XMLCDATASection
: '<' '!' ( 'CDATA' '[' XMLCDATASectionString? ']' )? '>'
;
XMLCDATASectionString
: '<Any XMLString that does not contain the string "]]>">'
;
XML-toegangsexpressies voor leden
Een XML-lidtoegangsexpressie heeft toegang tot de leden van een XML-waarde.
XMLMemberAccessExpression
: Expression '.' LineTerminator? '<' XMLQualifiedName '>'
| Expression '.' LineTerminator? '@' LineTerminator? '<' XMLQualifiedName '>'
| Expression '.' LineTerminator? '@' LineTerminator? IdentifierOrKeyword
| Expression '.' '.' '.' LineTerminator? '<' XMLQualifiedName '>'
;
Er zijn drie typen XML-toegangsexpressies voor leden:
Elementtoegang, waarin een XML-naam één punt volgt. Voorbeeld:
Dim customer = _ <customer> <name>Bob</> </> Dim customerName = customer.<name>.ValueToegang tot elementen wordt toegewezen aan de functie:
Function Elements(name As System.Xml.Linq.XName) As _ System.Collections.Generic.IEnumerable(Of _ System.Xml.Linq.XNode)Het bovenstaande voorbeeld is dus gelijk aan:
Dim customerName = customer.Elements("name").ValueKenmerktoegang, waarin een Visual Basic-id een punt en een bijteken volgt, of een XML-naam volgt een punt en een at-teken. Voorbeeld:
Dim customer = <customer age="30"/> Dim customerAge = customer.@ageKenmerktoegang wordt toegewezen aan de functie:
Function AttributeValue(name As System.Xml.Linq.XName) as StringHet bovenstaande voorbeeld is dus gelijk aan:
Dim customerAge = customer.AttributeValue("age")Opmerking. De
AttributeValueextensiemethode (evenals de gerelateerde extensie-eigenschapValue) is momenteel niet gedefinieerd in een assembly. Als de extensieleden nodig zijn, worden ze automatisch gedefinieerd in de assembly die wordt geproduceerd.Afdaalt de toegang af, waarbij een XML-naam drie puntjes volgt. Voorbeeld:
Dim company = _ <company> <customers> <customer>Bob</> <customer>Mary</> <customer>Joe</> </> </> Dim customers = company...<customer>Afdaalt de toegang tot de functie:
Function Descendents(name As System.Xml.Linq.XName) As _ System.Collections.Generic.IEnumerable(Of _ System.Xml.Linq.XElement)Het bovenstaande voorbeeld is dus gelijk aan:
Dim customers = company.Descendants("customer")
De basisexpressie van een XML-lidtoegangsexpressie moet een waarde zijn en moet van het type zijn:
Als een element of afstammend toegang,
System.Xml.Linq.XContainerof een afgeleid type, ofSystem.Collections.Generic.IEnumerable(Of T)een afgeleid type, waarbijTof een afgeleid type isSystem.Xml.Linq.XContainer.Als een kenmerktoegang,
System.Xml.Linq.XElementof een afgeleid type ofSystem.Collections.Generic.IEnumerable(Of T)een afgeleid type, waarbijTofSystem.Xml.Linq.XElementeen afgeleid type is.
Namen in XML-lidtoegangsexpressies mogen niet leeg zijn. Ze kunnen worden gekwalificeerd als naamruimte, met behulp van eventuele naamruimten die zijn gedefinieerd door de import. Voorbeeld:
Imports <xmlns:db="http://example.org/database">
Module Test
Sub Main()
Dim customer = _
<db:customer>
<db:name>Bob</>
</>
Dim name = customer.<db:name>
End Sub
End Module
Witruimte is niet toegestaan na de punt(en) in een XML-lidtoegangsexpressie of tussen de punthaken en de naam. Voorbeeld:
Dim customer = _
<customer age="30">
<name>Bob</>
</>
' All the following are error cases
Dim age = customer.@ age
Dim name = customer.< name >
Dim names = customer...< name >
Als de typen in de System.Xml.Linq naamruimte niet beschikbaar zijn, veroorzaakt een XML-lidtoegangsexpressie een compilatiefout.
Wacht op operator
De wachtoperator is gerelateerd aan asynchrone methoden, die worden beschreven in Sectie Async-methoden.
AwaitOperatorExpression
: 'Await' Expression
;
Await is een gereserveerd woord als de methode of lambda-expressie waarin deze wordt weergegeven, onmiddellijk een wijzigingsfunctie heeft Async , en als de Await expressie na die Async wijziging wordt weergegeven; deze is elders niet gereserveerd. Het is ook niet gereserveerd in preprocessorrichtlijnen. De wachtoperator is alleen toegestaan in de hoofdtekst van een methode of lambda-expressies waarin het een gereserveerd woord is. Binnen de onmiddellijk omsluitende methode of lambda kan een wachtexpressie niet voorkomen in de hoofdtekst van een Catch of Finally blok, noch in de hoofdtekst van een SyncLock instructie, noch in een query-expressie.
De wachtoperator gebruikt één expressie die moet worden geclassificeerd als een waarde en waarvan het type een te wachtend type moet zijn, of Object. Als het type is Object , wordt alle verwerking uitgesteld tot de runtime. Een type C wordt geacht te wachten als alle volgende waar zijn:
Cbevat een toegankelijke instantie of extensiemethode met de naamGetAwaitergeen argumenten en die een bepaald typeEretourneert;Ebevat een leesbare instantie of extensie-eigenschap met de naamIsCompleteddie geen argumenten accepteert en een booleaanse waarde heeft.Ebevat een toegankelijke instantie- of extensiemethode met de naamGetResultdie geen argumenten accepteert;EimplementeertSystem.Runtime.CompilerServices.INotifyCompletionofICriticalNotifyCompletion.
Als GetResult dit een Subis, wordt de await-expressie geclassificeerd als ongeldig. Anders wordt de await-expressie geclassificeerd als een waarde en het bijbehorende type is het retourtype van de GetResult methode.
Hier volgt een voorbeeld van een klasse die kan worden verwacht:
Class MyTask(Of T)
Function GetAwaiter() As MyTaskAwaiter(Of T)
Return New MyTaskAwaiter With {.m_Task = Me}
End Function
...
End Class
Structure MyTaskAwaiter(Of T)
Implements INotifyCompletion
Friend m_Task As MyTask(Of T)
ReadOnly Property IsCompleted As Boolean
Get
Return m_Task.IsCompleted
End Get
End Property
Sub OnCompleted(r As Action) Implements INotifyCompletion.OnCompleted
' r is the "resumptionDelegate"
Dim sc = SynchronizationContext.Current
If sc Is Nothing Then
m_Task.ContinueWith(Sub() r())
Else
m_Task.ContinueWith(Sub() sc.Post(Sub() r(), Nothing))
End If
End Sub
Function GetResult() As T
If m_Task.IsCanceled Then Throw New TaskCanceledException(m_Task)
If m_Task.IsFaulted Then Throw m_Task.Exception.InnerException
Return m_Task.Result
End Function
End Structure
Opmerking. Auteurs van bibliotheken worden aangeraden het patroon te volgen dat ze de vervolgdelegatie aanroepen op hetzelfde SynchronizationContext als waarop ze OnCompleted zelf zijn aangeroepen. De gemachtigde voor hervatting mag ook niet synchroon worden uitgevoerd binnen de OnCompleted methode, omdat dit kan leiden tot stackoverloop: in plaats daarvan moet de gedelegeerde in de wachtrij worden geplaatst voor volgende uitvoering.
Wanneer de besturingsstroom een Await operator bereikt, is het gedrag als volgt.
De
GetAwaitermethode van de await operand wordt aangeroepen. Het resultaat van deze aanroep wordt de wachter aangeduid.De eigenschap van
IsCompletedde wachter wordt opgehaald. Als het resultaat waar is, gaat u als volgt te werk:- De
GetResultmethode van de wachter wordt aangeroepen. AlsGetResulthet een functie was, is de waarde van de await-expressie de retourwaarde van deze functie.
- De
Als de eigenschap IsCompleted niet waar is, gaat u als volgt te werk:
Een van
ICriticalNotifyCompletion.UnsafeOnCompletedbeide wordt aangeroepen op de wachter (als het typeEvan de wachter wordt geïmplementeerdICriticalNotifyCompletion) ofINotifyCompletion.OnCompleted(anders). In beide gevallen wordt een hervattingsdelegering doorgegeven die is gekoppeld aan het huidige exemplaar van de asynchrone methode.Het besturingspunt van het huidige exemplaar van de asynchrone methode wordt onderbroken en de controlestroom wordt hervat in de huidige aanroeper (gedefinieerd in sectie-Async-methoden).
Als de gemachtigde voor hervatting later wordt aangeroepen,
- de hervattingsdelegatie herstelt
System.Threading.Thread.CurrentThread.ExecutionContexteerst naar wat op dat momentOnCompletedwerd aangeroepen, - vervolgens wordt de controlestroom hervat op het besturingspunt van het exemplaar van de asynchrone methode (zie Sectie Async-methoden),
- waar de
GetResultmethode van de wachter wordt aangeroepen, zoals in 2.1 hierboven.
- de hervattingsdelegatie herstelt
Als de wachtende operand het type Object heeft, wordt dit gedrag uitgesteld tot runtime:
- Stap 1 wordt bereikt door GetAwaiter() aan te roepen zonder argumenten; het kan daarom tijdens runtime binden aan exemplaarmethoden die optionele parameters gebruiken.
- Stap 2 wordt bereikt door de eigenschap IsCompleted() zonder argumenten op te halen en door een intrinsieke conversie naar Booleaanse waarde uit te voeren.
- Stap 3.a wordt uitgevoerd door te proberen
TryCast(awaiter, ICriticalNotifyCompletion), en als dit mislukt, danDirectCast(awaiter, INotifyCompletion).
De hervattingsdelegen die is doorgegeven in 3.a, kunnen slechts eenmaal worden aangeroepen. Als het meer dan één keer wordt aangeroepen, is het gedrag niet gedefinieerd.
Visual Basic language spec