Delen via


Expressies in Visual Basic

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, AddHandleren RemoveHandler instructies. 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 Nothing produceren 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, f wordt geïnterpreteerd als f() en f(Of Integer) wordt geïnterpreteerd als f(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 Module
    
  • Een 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:

    1. 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.

    2. Als het doeltype en System.Linq.Expressions.Expression(Of T)T een gemachtigde is, wordt de lambda-methode geïnterpreteerd alsof deze wordt gebruikt in expressies voor gedelegeerden T en 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 Sub kunnen 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, bijvoorbeeld New 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, bijvoorbeeld New 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 Object vervangen 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 Module
    
  • Een 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, f wordt geïnterpreteerd als f()).

  • Een eigenschapstoegang kan opnieuw worden geclassificeerd als een waarde. De eigenschapstoegangsexpressie wordt geïnterpreteerd als een aanroepexpressie van de Get toegangsfunctie 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:

    1. 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 heeftSystem.Collections.Generic.IList(Of T), IReadOnlyList(Of T)wordt IEnumerable(Of T)ICollection(Of T)IReadOnlyCollection(Of T)de letterlijke waarde van de matrix opnieuw geclassificeerd als een waarde van het type.T()

    2. 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, Object wordt 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 afgeleid Object() als het type in a versie 9.0 van de taal en Integer() 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 Nothing kan 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 type Object.

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 String naar deze regel zijn een uitzondering op deze regel en zijn alleen toegestaan voor null-waarden, omdat String conversies 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 -Not unaire 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.Chr als de constante waarde tussen 0 en 128 ligt; Microsoft.VisualBasic.Strings.AscW als de constante tekenreeks niet leeg is; Microsoft.VisualBasic.Strings.Asc als de constante tekenreeks niet leeg is.

De volgende constructies zijn niet toegestaan in constante expressies:

  • Impliciete binding via een With context.

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':

  1. 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 Get accessor de lokale variabele retourneert en de expressie deel uitmaakt van een aanroepexpressie, aanroepinstructie of een AddressOf expressie, 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.

  2. 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:

    1. 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.
    2. 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), waar E de id is en A de lijst met typeargumenten is, indien van toepassing.
    3. Anders is het resultaat precies hetzelfde als een lidtoegang van het formulier T.E(Of A), waar T het type is dat het overeenkomende lid bevat, E de id is en A de lijst met typeargumenten, indien van toepassing. In dit geval is het een fout voor de id om te verwijzen naar een niet-gedeeld lid.
  3. Ga voor elke geneste naamruimte vanaf de binnenste en naar de buitenste naamruimte als volgt te werk:

    1. 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.
    2. 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.
    3. 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), waarbij M de standaardmodule die het overeenkomende lid bevat, E de id is en A de 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.
  4. 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.

  5. Als het bronbestand met de naamreferentie een of meer importbewerkingen bevat:

    1. 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.
    2. 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.
    3. 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), waarbij M de standaardmodule die het overeenkomende lid bevat, E de id is en A de 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.
  6. 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.

  7. Als in de compilatieomgeving een of meer importbewerkingen worden gedefinieerd:

    1. 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.
    2. 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.
    3. 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), waarbij M de standaardmodule die het overeenkomende lid bevat, E de id is en A de 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.
  8. 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 GetType expressie het System.Type object 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:

  1. Als E u dit weglaat, wordt de expressie uit de direct bevattende With instructie vervangen E door en wordt de lidtoegang uitgevoerd. Als er geen instructie is, With treedt er een compilatiefout op.

  2. Als E deze is geclassificeerd als een naamruimte of E het trefwoord Globalis, wordt het opzoeken van leden uitgevoerd in de context van de opgegeven naamruimte. Als I dit 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.

  3. Als E dit 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. Als I dit de naam is van een toegankelijk lid van E, wordt deze E.I als volgt geëvalueerd en geclassificeerd:

    1. Als I het trefwoord New is en E geen opsomming is, treedt er een compileertijdfout op.
    2. Als I u een type identificeert met hetzelfde aantal typeparameters als is opgegeven in de lijst met typeargumenten, indien van toepassing, is het resultaat dat type.
    3. Als I een of meer methoden worden geïdentificeerd, is het resultaat een methodegroep met de lijst met gekoppelde typeargumenten en geen gekoppelde doelexpressie.
    4. Als I een of meer eigenschappen worden geïdentificeerd en er geen lijst met typeargumenten is opgegeven, is het resultaat een eigenschapsgroep zonder gekoppelde doelexpressie.
    5. Als I een 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 variabele I in E. Anders is het resultaat de gedeelde variabele I in E.
    6. Als I een gedeelde gebeurtenis wordt geïdentificeerd en er geen lijst met typeargumenten is opgegeven, is het resultaat een gebeurtenistoegang zonder gekoppelde doelexpressie.
    7. Als I een constante wordt geïdentificeerd en er geen lijst met typeargumenten is opgegeven, is het resultaat de waarde van die constante.
    8. Als I een opsommingslid wordt geïdentificeerd en er geen lijst met typeargumenten is opgegeven, is het resultaat de waarde van dat opsommingslid.
    9. Anders is E.I een ongeldige lidverwijzing en treedt er een compilatiefout op.
  4. Als E wordt geclassificeerd als een variabele of waarde, waarvan het type is T, wordt de opzoekactie van het lid uitgevoerd in de context van T. Als I dit de naam is van een toegankelijk lid van T, wordt deze E.I als volgt geëvalueerd en geclassificeerd:

    1. Als I het trefwoord New, E is Me, MyBaseof of MyClassen er geen typeargumenten zijn opgegeven, is het resultaat een methodegroep die de instantieconstructors vertegenwoordigt van het type van E het type met een gekoppelde doelexpressie van E en geen type argumentlijst. Anders treedt er een compilatietijdfout op.
    2. Als I een of meer methoden worden geïdentificeerd, inclusief uitbreidingsmethoden als T dat niet Objectzo is, is het resultaat een methodegroep met de lijst met gekoppelde typeargumenten en een bijbehorende doelexpressie van E.
    3. Als I een of meer eigenschappen worden geïdentificeerd en er geen typeargumenten zijn opgegeven, is het resultaat een eigenschapsgroep met een bijbehorende doelexpressie van E.
    4. Als I een 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 variabele I in het object waarnaar Ewordt verwezen. Als T dit een verwijzingstype is, is het resultaat de variabele I in het object waarnaar wordt verwezen.E T Als dit niet het waardetype is en de expressie E wordt geclassificeerd als een variabele, is het resultaat een variabele. Anders is het resultaat een waarde.
    5. Als I een gebeurtenis wordt geïdentificeerd en er geen typeargumenten zijn opgegeven, is het resultaat een gebeurtenistoegang met een bijbehorende doelexpressie van E.
    6. Als I een constante wordt geïdentificeerd en er geen typeargumenten zijn opgegeven, is het resultaat de waarde van die constante.
    7. Als I een opsommingslid wordt geïdentificeerd en er geen typeargumenten zijn opgegeven, is het resultaat de waarde van dat opsommingslid.
    8. Als T dat het is Object, 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 van E.
  5. Anders is E.I een 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 TypeToCollect geeft 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 CreateInstanceMethodName geeft de methode op die moet worden aangeroepen in de groepsklasse om een nieuw exemplaar te maken in een standaardexemplareneigenschap.

  • Met de parameter DisposeInstanceMethodName wordt de methode opgegeven die moet worden aangeroepen in de groepsklasse om een standaardexemplareneigenschap te verwijderen als aan de standaardexemplareneigenschap de waarde Nothingwordt toegewezen.

  • De parameter DefaultInstanceAlias specificeert de expressie E' die moet worden vervangen door de klassenaam als de standaardexemplaren rechtstreeks toegankelijk zijn via hun typenaam. Als deze parameter of een lege tekenreeks is Nothing , 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 de DefaultInstanceAlias parameter 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:

  1. Eerst wordt elk geneste type met de expressie gecontroleerd, te beginnen bij de binnenste en naar de buitenste.
  2. Vervolgens wordt elke geneste naamruimte gecontroleerd, te beginnen bij de binnenste en naar de buitenste naamruimte te gaan.
  3. Vervolgens worden de importbewerkingen in het bronbestand gecontroleerd.
  4. 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, Objectof System.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.IndexOutOfRangeException uitzondering gegenereerd. Elke expressie moet impliciet worden geconverteerd om te typen Integer. 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 Get accessor 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 Object of System.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 als Object. 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.AmbiguousMatchException uitzondering gegenereerd. Vervolgens wordt het resultaat verwerkt als een eigenschapstoegang of als aanroep en wordt het resultaat geretourneerd. Als de aanroep van een subroutine is, is Nothinghet 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.MissingMemberException uitzondering 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:

  • M is niet Partial of heeft een lichaam.

  • Beide M functies D of D zijn een subroutine.

  • M en D hetzelfde aantal parameters hebben.

  • De parametertypen van M elk hebben een conversie van het type van het overeenkomstige parametertype vanD, en hun modifiers (dat wil ByRefByValbijvoorbeeld ) overeenkomst.

  • Het retourtype van M, indien aanwezig, heeft een conversie naar het retourtype D.

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 M een widening conversie naar het bijbehorende parametertype van D.

  • Of, het retourtype, indien van toepassing, M heeft een smalle conversie naar het retourtype van D.

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 L er parameters zijn, D heeft u hetzelfde aantal parameters. (Als L er geen parameters zijn, worden de parameters D genegeerd.)

  • De parametertypen van L elk hebben een conversie naar het type van het overeenkomstige parametertype vanD, en de bijbehorende modifiers (dat wil ByRefByValbijvoorbeeld , ) overeenkomst.

  • Als D dit een functie is, heeft het retourtype L een conversie naar het retourtype .D (Als D dit een subroutine is, wordt de retourwaarde L genegeerd.)

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 x wordt de naam xafgeleid.

  • De naam ywordt afgeleid door een toegangsexpressie x.y voor leden.

  • Met een opzoekexpressie x!y voor woordenlijst wordt de naam yafgeleid.

  • Een aanroep- of indexexpressie zonder argumenten x() afleiden de naam x.

  • Met een XML-lidtoegangsexpressie x.<y>wordt x...<y>x.@y de naam yafgeleid.

  • Een XML-lidtoegangsexpressie die het doel is van een toegangsexpressie x.<y>.z voor leden, bepaalt de naam z.

  • Een XML-lidtoegangsexpressie die het doel is van een aanroep- of indexexpressie zonder argumenten x.<y>.z() , bepaalt de naam z.

  • Een XML-lidtoegangsexpressie die het doel is van een aanroep- of indexexpressie x.<y>(0) , bepaalt de naam y.

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:

  1. 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.

  2. 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, Noten AndOr mogelijk 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, ULong en Long. Als de controle van een overloop van gehele getallen is ingeschakeld en de som buiten het bereik van het resultaattype valt, wordt er een System.OverflowException uitzondering gegenereerd. Anders worden overloop niet gerapporteerd en worden belangrijke bits van het resultaat verwijderd.

  • Single en Double. 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 een System.OverflowException uitzondering gegenereerd. Als de resultaatwaarde te klein is om weer te geven in de decimale notatie, is het resultaat 0.

  • String. De twee String operanden worden samengevoegd.

  • Date. Het System.DateTime type definieert overbelaste toevoegingsoperatoren. Omdat System.DateTime dit gelijk is aan het intrinsieke Date type, zijn deze operators ook beschikbaar voor het Date type.

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, ULong en Long. Als controle op gehele getallen overloop is ingeschakeld en het verschil buiten het bereik van het resultaattype valt, wordt er een System.OverflowException uitzondering gegenereerd. Anders worden overloop niet gerapporteerd en worden belangrijke bits van het resultaat verwijderd.

  • Single en Double. 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 een System.OverflowException uitzondering gegenereerd. Als de resultaatwaarde te klein is om weer te geven in de decimale notatie, is het resultaat 0.

  • Date. Het System.DateTime type definieert overbelaste aftrekkingsoperators. Omdat System.DateTime dit gelijk is aan het intrinsieke Date type, zijn deze operators ook beschikbaar voor het Date type.

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, ULong en Long. Als controle op overloop op gehele getallen is ingeschakeld en het product zich buiten het bereik van het resultaattype bevindt, wordt er een System.OverflowException uitzondering gegenereerd. Anders worden overloop niet gerapporteerd en worden belangrijke bits van het resultaat verwijderd.

  • Single en Double. 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 een System.OverflowException uitzondering 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:

  • Single en Double. Het quotiënt wordt berekend volgens de regels van IEEE 754-rekenkundige bewerkingen.

  • Decimal. Als de waarde van de rechteroperand nul is, wordt er een System.DivideByZeroException uitzondering gegenereerd. Als de resulterende waarde te groot is om weer te geven in de decimale notatie, wordt er een System.OverflowException uitzondering 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, en LongIntegerULong . Het resultaat van x Mod y is de waarde die wordt geproduceerd door x - (x \ y) * y. Als y nul is, wordt er een System.DivideByZeroException uitzondering gegenereerd. De modulo-operator veroorzaakt nooit een overloop.

  • Single en Double. De rest wordt berekend volgens de regels van IEEE 754-rekenkundige berekeningen.

  • Decimal. Als de waarde van de rechteroperand nul is, wordt er een System.DivideByZeroException uitzondering gegenereerd. Als de resulterende waarde te groot is om weer te geven in de decimale notatie, wordt er een System.OverflowException uitzondering 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. True wordt beschouwd als kleiner dan False, die overeenkomt met hun numerieke waarden.

  • Byte, SByte, UShort, Short, UInteger, Integer, ULong en Long. De operators vergelijken de numerieke waarden van de twee integrale operanden.

  • Single en Double. 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 de Option Compare instructie. 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 Boolean type:

    • Er wordt een logische And bewerking uitgevoerd op de twee operanden.

    • Er wordt een logische Not bewerking uitgevoerd op de operand.

    • Er wordt een logische Or bewerking uitgevoerd op de twee operanden.

    • Een logische exclusieveOr bewerking wordt uitgevoerd op de twee operanden.

  • Voor Byte, SByte, UShort, Short, , UInteger, , Integer, , ULongen Longalle 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: 1 Xor 0 = 1, 1 Xor 1 = 0).

  • Wanneer de logische operators And worden opgeheven en Or voor het type Boolean?worden opgeheven, worden ze uitgebreid tot booleaanse logica met drie waarden als zodanig:

    • And resulteert in waar als beide operanden waar zijn; onwaar als een van de operanden onwaar is; Nothing anders.

    • Or resulteert in waar als een van beide operanden waar is; false is beide operanden onwaar; Nothing anders.

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 AndAlso bewerking Waar oplevert False of retourneert vanuit IsFalse de operator, retourneert de expressie de eerste operand. Anders wordt de tweede operand geëvalueerd en wordt een logische And bewerking uitgevoerd op de twee resultaten.

  • Als de eerste operand in een OrElse bewerking Waar oplevert True of retourneert vanuit IsTrue de operator, retourneert de expressie de eerste operand. Anders wordt de tweede operand geëvalueerd en wordt een logische Or bewerking 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:

  • T is Boolean of Boolean?

  • T heeft een brede conversie naar Boolean

  • T heeft een brede conversie naar Boolean?

  • T definieert twee pseudooperators, IsTrue en IsFalse.

  • T heeft een vermalingsconversie naar Boolean? die geen conversie van Boolean naar Boolean?.

  • T heeft een narrowing conversie naar Boolean.

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 Return instructies in het instructieblok.

  • In een asynchrone lambda-expressie is Task(Of T) het retourtype waar T het dominante type expressies in alle Return instructies in het instructieblok is.

  • In een iterator lambda-expressie is IEnumerable(Of T) het retourtype het T dominante type van de expressies in alle Yield instructies 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 Error en Resume instructies zijn niet toegestaan, hoewel Try instructies 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 type Me geen 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 overeenkomende Func type.

  • Het type System.Linq.Expressions.Expression(Of D) kan worden gebruikt in plaats van het type gemachtigde Func , mits dit D een gemachtigdentype is met dezelfde handtekening, inclusief het retourtype, als het overeenkomende Func type.

  • Het type T vertegenwoordigt 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 S vertegenwoordigt het elementtype van de tweede invoerverzameling in het geval van queryoperators die joins uitvoeren.

  • Het type K vertegenwoordigt een sleuteltype in het geval van queryoperators met een set bereikvariabelen die fungeren als sleutels.

  • Het type N vertegenwoordigt 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 B vertegenwoordigt een type dat kan worden gebruikt in een Boole-expressie.

  • Het type R vertegenwoordigt het elementtype van de resultaatverzameling als de queryoperator een resultaatverzameling produceert. R is afhankelijk van het aantal bereikvariabelen binnen het bereik aan de conclusie van de queryoperator. Als één bereikvariabele binnen het bereik valt, is dit R het type bereikvariabele. In het voorbeeld

    Dim custNames = From c In Customers
                    Select c.Name
    

    het resultaat van de query is een verzamelingstype met een elementtype.String Als meerdere bereikvariabelen binnen het bereik vallen, is dit R een anoniem type dat alle bereikvariabelen in het bereik als Key velden bevat. In het voorbeeld:

    Dim custNames = From c In Customers, o In c.Orders 
                    Select Name = c.Name, ProductName = o.ProductName
    

    het resultaat van de query is een verzamelingstype met een elementtype van een anoniem type met een alleen-lezen eigenschap met de naam Name van het type String en een alleen-lezen eigenschap met de naam ProductName van het type String.

    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 c bijvoorbeeld toegankelijk zonder o kwalificatie in de Select queryoperator, ook al was het elementtype van de invoerverzameling een anoniem type.

  • Het type CX vertegenwoordigt een verzamelingstype, niet noodzakelijkerwijs het invoerverzamelingstype, waarvan het elementtype een bepaald type Xis.

Een opvraagbaar verzamelingstype moet voldoen aan een van de volgende voorwaarden, in volgorde van voorkeur:

  • Er moet een conforme Select methode worden gedefinieerd.

  • Het moet een van de volgende methoden hebben

    Function AsEnumerable() As CT
    Function AsQueryable() As CT
    

    die kan worden aangeroepen om een opvraagbare verzameling te verkrijgen. Als beide methoden worden opgegeven, AsQueryable heeft de voorkeur boven AsEnumerable.

  • Het moet een methode hebben

    Function Cast(Of T)() As CT
    

    die 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>.Value
    

    Toegang 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").Value
    
  • Kenmerktoegang, 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.@age
    

    Kenmerktoegang wordt toegewezen aan de functie:

    Function AttributeValue(name As System.Xml.Linq.XName) as String
    

    Het bovenstaande voorbeeld is dus gelijk aan:

    Dim customerAge = customer.AttributeValue("age")
    

    Opmerking. De AttributeValue extensiemethode (evenals de gerelateerde extensie-eigenschap Value) 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.XContainer of een afgeleid type, of System.Collections.Generic.IEnumerable(Of T) een afgeleid type, waarbij T of een afgeleid type is System.Xml.Linq.XContainer .

  • Als een kenmerktoegang, System.Xml.Linq.XElement of een afgeleid type of System.Collections.Generic.IEnumerable(Of T) een afgeleid type, waarbij T of System.Xml.Linq.XElement een 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:

  • C bevat een toegankelijke instantie of extensiemethode met de naam GetAwaiter geen argumenten en die een bepaald type Eretourneert;

  • E bevat een leesbare instantie of extensie-eigenschap met de naam IsCompleted die geen argumenten accepteert en een booleaanse waarde heeft.

  • E bevat een toegankelijke instantie- of extensiemethode met de naam GetResult die geen argumenten accepteert;

  • E implementeert System.Runtime.CompilerServices.INotifyCompletion of ICriticalNotifyCompletion.

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.

  1. De GetAwaiter methode van de await operand wordt aangeroepen. Het resultaat van deze aanroep wordt de wachter aangeduid.

  2. De eigenschap van IsCompleted de wachter wordt opgehaald. Als het resultaat waar is, gaat u als volgt te werk:

    1. De GetResult methode van de wachter wordt aangeroepen. Als GetResult het een functie was, is de waarde van de await-expressie de retourwaarde van deze functie.
  3. Als de eigenschap IsCompleted niet waar is, gaat u als volgt te werk:

    1. Een van ICriticalNotifyCompletion.UnsafeOnCompleted beide wordt aangeroepen op de wachter (als het type E van de wachter wordt geïmplementeerd ICriticalNotifyCompletion) of INotifyCompletion.OnCompleted (anders). In beide gevallen wordt een hervattingsdelegering doorgegeven die is gekoppeld aan het huidige exemplaar van de asynchrone methode.

    2. 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).

    3. Als de gemachtigde voor hervatting later wordt aangeroepen,

      1. de hervattingsdelegatie herstelt System.Threading.Thread.CurrentThread.ExecutionContext eerst naar wat op dat moment OnCompleted werd aangeroepen,
      2. vervolgens wordt de controlestroom hervat op het besturingspunt van het exemplaar van de asynchrone methode (zie Sectie Async-methoden),
      3. waar de GetResult methode van de wachter wordt aangeroepen, zoals in 2.1 hierboven.

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, dan DirectCast(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.