Uttryck i Visual Basic

Ett uttryck är en sekvens av operatorer och operander som anger en beräkning av ett värde, eller som anger en variabel eller konstant. I det här kapitlet definieras syntax, ordning för utvärdering av operander och operatorer samt innebörden av uttryck.

Expression
    : SimpleExpression
    | TypeExpression
    | MemberAccessExpression
    | DictionaryAccessExpression
    | InvocationExpression
    | IndexExpression
    | NewExpression
    | CastExpression
    | OperatorExpression
    | ConditionalExpression
    | LambdaExpression
    | QueryExpression
    | XMLLiteralExpression
    | XMLMemberAccessExpression
    ;

Uttrycksklassificeringar

Varje uttryck klassificeras som något av följande:

  • Ett värde. Varje värde har en associerad typ.

  • En variabel. Varje variabel har en associerad typ, nämligen variabelns deklarerade typ.

  • Ett namnområde. Ett uttryck med den här klassificeringen kan bara visas som vänster sida av en medlemsåtkomst. I andra sammanhang orsakar ett uttryck som klassificeras som ett namnområde ett kompileringsfel.

  • En typ. Ett uttryck med den här klassificeringen kan bara visas som vänster sida av en medlemsåtkomst. I andra sammanhang orsakar ett uttryck som klassificeras som en typ ett kompileringsfel.

  • En metodgrupp, som är en uppsättning metoder som är överbelastade med samma namn. En metodgrupp kan ha ett associerat måluttryck och en argumentlista av associerad typ.

  • En metodpekare som representerar platsen för en metod. En metodpekare kan ha ett associerat måluttryck och en argumentlista av associerad typ.

  • En lambda-metod, som är en anonym metod.

  • En egenskapsgrupp, som är en uppsättning egenskaper som är överbelastade med samma namn. En egenskapsgrupp kan ha ett associerat måluttryck.

  • En egenskapsåtkomst. Varje egenskapsåtkomst har en associerad typ, nämligen egenskapens typ. En egenskapsåtkomst kan ha ett associerat måluttryck.

  • En sen bunden åtkomst, som representerar en metod- eller egenskapsåtkomst som skjuts upp till körning. En sen bunden åtkomst kan ha ett associerat måluttryck och en argumentlista av associerad typ. Typen av sen åtkomst är alltid Object.

  • Tillgång till ett evenemang Varje händelseåtkomst har en associerad typ, nämligen typen av händelse. En händelseåtkomst kan ha ett associerat måluttryck. En händelseåtkomst kan visas som det första argumentet i - och AddHandlerRemoveHandler -uttryckenRaiseEvent. I andra sammanhang orsakar ett uttryck som klassificeras som en händelseåtkomst ett kompileringsfel.

  • En matrisliteral som representerar de inledande värdena för en matris vars typ ännu inte har fastställts.

  • Tomrum. Detta inträffar när uttrycket är ett anrop av en subrutin eller ett väntande operatoruttryck utan resultat. Ett uttryck som klassificeras som void är endast giltigt i kontexten för en anropsinstruktur eller en await-instruktion.

  • Ett standardvärde. Endast literalen Nothing genererar den här klassificeringen.

Slutresultatet av ett uttryck är vanligtvis ett värde eller en variabel, där de andra uttryckskategorierna fungerar som mellanliggande värden som endast tillåts i vissa kontexter.

Observera att uttryck vars typ är en typparameter kan användas i instruktioner och uttryck som kräver att typen av ett uttryck har vissa egenskaper (till exempel att vara en referenstyp, värdetyp, härleda från någon typ osv.) om begränsningarna för typparametern uppfyller dessa egenskaper.

Omklassificering av uttryck

Normalt, när ett uttryck används i en kontext som kräver en annan klassificering än uttryckets, uppstår ett kompileringsfel , till exempel försök att tilldela ett värde till en literal. I många fall är det dock möjligt att ändra ett uttrycks klassificering genom omklassificeringsprocessen.

Om omklassificeringen lyckas bedöms omklassificeringen som bredare eller smalare. Om inget annat anges utvidgas alla omklassificeringar i den här listan.

Följande typer av uttryck kan omklassificeras:

  • En variabel kan omklassificeras som ett värde. Värdet som lagras i variabeln hämtas.

  • En metodgrupp kan omklassificeras som ett värde. Metodgrupputtrycket tolkas som ett anropsuttryck med det associerade måluttrycket och typparameterlistan och tomma parenteser (d.s f . tolkas som f() och f(Of Integer) tolkas som f(Of Integer)()). Den här omklassificeringen kan leda till att uttrycket omklassificeras ytterligare som void.

  • En metodpekare kan omklassificeras som ett värde. Den här omklassificeringen kan bara ske i samband med en konvertering där måltypen är känd. Metodpekaruttrycket tolkas som argumentet till ett ombuds-instansieringsuttryck av lämplig typ med den associerade typargumentlistan. Till exempel:

    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
    
  • En lambda-metod kan omklassificeras som ett värde. Om omklassificeringen sker i samband med en konvertering där måltypen är känd kan en av två omklassificeringar ske:

    1. Om måltypen är en ombudstyp tolkas lambda-metoden som argumentet till ett ombudskonstruktionsuttryck av lämplig typ.

    2. Om måltypen är System.Linq.Expressions.Expression(Of T), och T är en ombudstyp, tolkas lambda-metoden som om den användes i uttrycket delegate-construction för T och konverteras sedan till ett uttrycksträd.

    En asynkron eller iterator lambda-metod kan bara tolkas som argumentet till ett delegatkonstruktionsuttryck, om ombudet inte har några ByRef-parametrar.

    Om konvertering från någon av ombudets parametertyper till motsvarande lambda-parametertyper är en begränsad konvertering, bedöms omklassificeringen som begränsad. annars utvidgas den.

    Observera. Den exakta översättningen mellan lambda-metoder och uttrycksträd kanske inte är fast mellan versioner av kompilatorn och ligger utanför den här specifikationens omfång. För Microsoft Visual Basic 11.0 kan alla lambda-uttryck konverteras till uttrycksträd som omfattas av följande begränsningar: (1) 1. Endast lambda-uttryck med en rad utan ByRef-parametrar kan konverteras till uttrycksträd. Av enrads Sub lambdas kan endast anropssatser konverteras till uttrycksträd. (2) Anonyma typuttryck kan inte konverteras till uttrycksträd om en tidigare fältinitierare används för att initiera en efterföljande fältinitierare, t.ex. New With {.a=1, .b=.a}. (3) Objektinitieringsuttryck kan inte konverteras till uttrycksträd om en medlem i det aktuella objektet som initieras används i någon av fältinitierarna, t.ex. New C1 With {.a=1, .b=.Method1()}. (4) Flerdimensionella uttryck för skapande av matriser kan bara konverteras till uttrycksträd om de deklarerar sin elementtyp explicit. (5) Uttryck med sen bindning kan inte konverteras till uttrycksträd. (6) När en variabel eller ett fält skickas byref till ett anropsuttryck men inte har exakt samma typ som ByRef-parametern, eller när en egenskap skickas byref, är normala VB-semantik att en kopia av argumentet skickas ByRef och dess slutliga värde sedan kopieras tillbaka till variabeln eller fältet eller egenskapen. I uttrycksträd sker inte återkopiering. (7) Alla dessa begränsningar gäller även för kapslade lambdauttryck.

    Om måltypen inte är känd tolkas lambda-metoden som argumentet till ett delegat-instansieringsuttryck av en anonym delegattyp med samma signatur för lambda-metoden. Om strikt semantik används och typen av någon av parametrarna utelämnas uppstår ett kompileringsfel. I annat fall Object ersätts parametertypen saknas. Till exempel:

    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
    
  • En egenskapsgrupp kan omklassificeras som en egenskapsåtkomst. Egenskapsgrupputtrycket tolkas som ett indexuttryck med tomma parenteser (d.s f . tolkas som f()).

  • En egenskapsåtkomst kan omklassificeras som ett värde. Egenskapsåtkomstuttrycket tolkas som ett anropsuttryck för Get egenskapens accessor. Om egenskapen inte har någon getter uppstår ett kompileringsfel.

  • En sen bindningsåtkomst kan omklassificeras som en sen bindningsmetod eller åtkomst till en sen bindningsegenskap. I en situation där en sen bunden åtkomst kan omklassificeras både som en metodåtkomst och som en egenskapsåtkomst, rekommenderas omklassificering till en egenskapsåtkomst.

  • En sen bunden åtkomst kan omklassificeras som ett värde.

  • En matrisliteral kan omklassificeras som ett värde. Värdets typ bestäms på följande sätt:

    1. Om omklassificeringen sker i kontexten för en konvertering där måltypen är känd och måltypen är en matristyp, omklassificeras matrisliteralen som ett värde av typen T(). Om måltypen är System.Collections.Generic.IList(Of T), IReadOnlyList(Of T), ICollection(Of T), IReadOnlyCollection(Of T)eller och IEnumerable(Of T)matrisliteralen har en kapslingsnivå, omklassificeras matrisliteralen som ett värde av typen T().

    2. Annars omklassificeras matrisliteralen till ett värde vars typ är en matris med rangordning som är lika med kapslingsnivån, där elementtypen bestäms av den dominerande typen av element i initiatorn. om ingen dominerande typ kan fastställas, Object används. Till exempel:

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

    Observera. Det finns en liten förändring i beteendet mellan version 9.0 och version 10.0 av språket. Före 10.0 påverkade initiering av matriselement inte den lokala variabeltypens slutsatsdragning och det gör de nu. Så Dim a() = { 1, 2, 3 } skulle ha härledts Object() som typ av a i version 9.0 av språket och Integer() i version 10.0.

    Omklassificeringen omtolkar sedan matrisliteralen som ett uttryck för att skapa matriser. Så exemplen:

    Dim x As Double = { 1, 2, 3, 4 }
    Dim y = { "a", "b" }
    

    motsvarar:

    Dim x As Double = New Double() { 1, 2, 3, 4 }
    Dim y = New String() { "a", "b" }
    

    Omklassificeringen bedöms som begränsad om någon konvertering från ett elementuttryck till matriselementtypen minskar. annars bedöms det som en breddning.

  • Standardvärdet Nothing kan omklassificeras som ett värde. I en kontext där måltypen är känd är resultatet standardvärdet för måltypen. I en kontext där måltypen inte är känd är resultatet ett null-värde av typen Object.

Det går inte att omklassificera ett namnområdesuttryck, typuttryck, händelseåtkomstuttryck eller void-uttryck. Flera omklassificeringar kan göras samtidigt. Till exempel:

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

I det här fallet omklassificeras egenskapsgrupputtrycket P först från en egenskapsgrupp till en egenskapsåtkomst och omklassificeras sedan från en egenskapsåtkomst till ett värde. Det minsta antalet omklassificeringar utförs för att nå en giltig klassificering i kontexten.

Konstanta uttryck

Ett konstant uttryck är ett uttryck vars värde kan utvärderas fullständigt vid kompileringstillfället.

ConstantExpression
    : Expression
    ;

Typen av ett konstant uttryck kan vara Byte, SByte, UShort, Short, UInteger, Integer, ULong, Long, , Char, Single, Double, Decimal, Date, Boolean, String, , Objecteller någon uppräkningstyp. Följande konstruktioner tillåts i konstanta uttryck:

  • Literaler (inklusive Nothing).

  • Referenser till medlemmar av konstant typ eller konstanta lokalbefolkningen.

  • Referenser till medlemmar i uppräkningsdatatyper.

  • Parentesiserade underuttryck.

  • Tvångsuttryck, förutsatt att måltypen är en av de typer som anges ovan. Tvång till och från String är ett undantag från den här regeln och tillåts endast för null-värden eftersom String konverteringar alltid görs i den aktuella kulturen i körningsmiljön vid körning. Observera att konstanta tvångsuttryck bara kan använda inbyggda konverteringar.

  • Operatorerna +, - och Not unary, förutsatt att operand och resultat är av en typ som anges ovan.

  • Operatorerna +, , -, ^*, Mod, \/, <<, >>, &, And, Or, , Xor, OrElseAndAlso, =, <><>, och <==> binära operatorer, förutsatt att varje operand och resultat är av en typ som anges ovan.

  • Villkorsoperatorn If, förutsatt att varje operand och resultat är av en typ som anges ovan.

  • Följande körningsfunktioner: Microsoft.VisualBasic.Strings.ChrW; Microsoft.VisualBasic.Strings.Chr om konstantvärdet är mellan 0 och 128, Microsoft.VisualBasic.Strings.AscW om konstantsträngen inte är tom, Microsoft.VisualBasic.Strings.Asc om konstantsträngen inte är tom.

Följande konstruktioner tillåts inte i konstanta uttryck:

  • Implicit bindning via en With kontext.

Konstanta uttryck av en integraltyp (ULong, Long, UInteger, Integer, UShort, Short, SByteeller Byte) kan implicit konverteras till en smalare integraltyp, och konstanta uttryck av typen Double kan implicit konverteras till , förutsatt att Singlevärdet för det konstanta uttrycket ligger inom måltypens intervall. Dessa begränsade konverteringar tillåts oavsett om tillåtande eller strikt semantik används.

Late-Bound uttryck

När målet för ett medlemsåtkomstuttryck eller indexuttryck är av typen Objectkan bearbetningen av uttrycket skjutas upp till körningstiden. Att skjuta upp bearbetningen på det här sättet kallas för sen bindning. Med sen bindning kan Object variabler användas på ett typlöst sätt, där alla medlemmars upplösning baseras på den faktiska körningstypen för värdet i variabeln. Om strikt semantik anges av kompileringsmiljön eller av Option Strictorsakar sen bindning ett kompileringsfel. Icke-offentliga medlemmar ignoreras när de utför sen bindning, inklusive för överbelastningsmatchning. Observera att anropsmålet utvärderas vid körning, till skillnad från det tidiga fallet, att anropa eller komma åt en Shared medlem som är sen bunden. Om uttrycket är ett anropsuttryck för en medlem som definierats i System.Objectsker inte sen bindning.

I allmänhet löses senbundna åtkomster vid körning genom att söka efter identifieraren för uttryckets faktiska körningstyp. Om den sena medlemssökningen misslyckas vid körningen genereras ett System.MissingMemberException undantag. Eftersom late-bound member lookup görs enbart utanför körningstypen för det associerade måluttrycket är ett objekts körningstyp aldrig ett gränssnitt. Därför är det omöjligt att komma åt gränssnittsmedlemmar i ett sent medlemsåtkomstuttryck.

Argumenten till en sen bunden medlemsåtkomst utvärderas i den ordning de visas i medlemsåtkomstuttrycket: inte i vilken ordning parametrar deklareras i den sena medlemmen. I följande exempel visas den här skillnaden:

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

Den här koden visar:

Early-bound: xy
Late-bound: yx

Eftersom fördröjd överbelastningsmatchning utförs på körningstypen för argumenten är det möjligt att ett uttryck kan ge olika resultat baserat på om det utvärderas vid kompileringstid eller körningstid. I följande exempel visas den här skillnaden:

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

Den här koden visar:

F(Base)
F(Derived)

Enkla uttryck

Enkla uttryck är literaler, parenteserade uttryck, instansuttryck eller enkla namnuttryck.

SimpleExpression
    : LiteralExpression
    | ParenthesizedExpression
    | InstanceExpression
    | SimpleNameExpression
    | AddressOfExpression
    ;

Literaluttryck

Literaluttryck utvärderas till det värde som representeras av literalen. Ett literaluttryck klassificeras som ett värde, förutom literalen Nothing, som klassificeras som ett standardvärde.

LiteralExpression
    : Literal
    ;

Parenteserade uttryck

Ett parentesiserat uttryck består av ett uttryck som omges av parenteser. Ett parenteserat uttryck klassificeras som ett värde och det omgivna uttrycket måste klassificeras som ett värde. Ett parentesiserat uttryck utvärderas till värdet för uttrycket inom parenteserna.

ParenthesizedExpression
    : OpenParenthesis Expression CloseParenthesis
    ;

Instansuttryck

Ett instansuttryck är nyckelordet Me. Den får endast användas i brödtexten för en icke-delad metod, konstruktor eller egenskapsåtkomst. Det klassificeras som ett värde. Me Nyckelordet representerar den instans av typen som innehåller den metod eller egenskapsåtkomst som körs. Om en konstruktor uttryckligen anropar en annan konstruktor ( avsnittskonstruktorer) Me kan den inte användas förrän efter konstruktoranropet, eftersom instansen ännu inte har konstruerats.

InstanceExpression
    : 'Me'
    ;

Enkla namnuttryck

Ett enkelt namnuttryck består av en enda identifierare följt av en valfri typargumentlista.

SimpleNameExpression
    : Identifier ( OpenParenthesis 'Of' TypeArgumentList CloseParenthesis )?
    ;

Namnet matchas och klassificeras av följande "regler för enkel namnmatchning":

  1. Om identifieraren börjar med det omedelbart omslutande blocket och fortsätter med varje omslutande yttre block (om det finns något), om identifieraren matchar namnet på en lokal variabel, statisk variabel, konstant lokal parameter, metodtypparameter eller parameter, refererar identifieraren till den matchande entiteten.

    Om identifieraren matchar en lokal variabel, statisk variabel eller konstant lokal och en typargumentlista angavs uppstår ett kompileringsfel. Om identifieraren matchar en metodtypparameter och en typargumentlista angavs sker ingen matchning och lösningen fortsätter. Om identifieraren matchar en lokal variabel är den lokala variabeln som matchas den implicita funktionen eller Get accessorn returnerar lokal variabel, och uttrycket är en del av ett anropsuttryck, en anropsinstrukation eller ett AddressOf uttryck, så sker ingen matchning och upplösningen fortsätter.

    Uttrycket klassificeras som en variabel om det är en lokal variabel, statisk variabel eller parameter. Uttrycket klassificeras som en typ om det är en metodtypparameter. Uttrycket klassificeras som ett värde om det är en konstant lokal.

  2. För varje kapslad typ som innehåller uttrycket, med början från den innersta och går till den yttersta, om en sökning av identifieraren i typen ger en matchning med en tillgänglig medlem:

    1. Om den matchande typmedlemmen är en typparameter klassificeras resultatet som en typ och är den matchande typparametern. Om en typargumentlista angavs sker ingen matchning och lösningen fortsätter.
    2. Annars, om typen är den omedelbart omslutande typen och sökningen identifierar en icke-delad typmedlem, blir resultatet samma som en medlemsåtkomst för formuläret Me.E(Of A), där E är identifieraren och A är typargumentlistan, om någon.
    3. Annars är resultatet exakt samma som en medlemsåtkomst i formuläret T.E(Of A), där T är den typ som innehåller den matchande medlemmen, E är identifieraren och A är typargumentlistan, om någon. I det här fallet är det ett fel för identifieraren att referera till en icke-delad medlem.
  3. Gör följande för varje kapslad namnrymd, från den innersta och gå till det yttersta namnområdet:

    1. Om namnområdet innehåller en tillgänglig typ med det angivna namnet och har samma antal typparametrar som angavs i typargumentlistan, om någon, refererar identifieraren till den typen och klassificeras som en typ.
    2. Annars, om ingen typargumentlista angavs och namnområdet innehåller en namnområdesmedlem med det angivna namnet, refererar identifieraren till namnområdet och klassificeras som ett namnområde.
    3. Annars, om namnområdet innehåller en eller flera tillgängliga standardmoduler, och ett medlemsnamnsökning av identifieraren ger en tillgänglig matchning i exakt en standardmodul, blir resultatet exakt samma som en medlemsåtkomst för formuläret M.E(Of A), där M är standardmodulen som innehåller den matchande medlemmen, E är identifieraren och A är typargumentlistan, om det finns några. Om identifieraren matchar medlemmar av tillgänglig typ i mer än en standardmodul uppstår ett kompileringsfel.
  4. Om källfilen har ett eller flera importalias och identifieraren matchar namnet på ett av dem refererar identifieraren till namnområdet eller typen. Om en typargumentlista anges uppstår ett kompileringsfel.

  5. Om källfilen som innehåller namnreferensen har en eller flera importer:

    1. Om identifieraren matchar i exakt en import av namnet på en tillgänglig typ med samma antal typparametrar som angavs i typargumentlistan, om någon, eller en typmedlem, refererar identifieraren till den typen eller typmedlemmen. Om identifieraren matchar i mer än en import av namnet på en tillgänglig typ med samma antal typparametrar som angavs i typargumentlistan, om någon, eller en medlem av tillgänglig typ, uppstår ett kompileringsfel.
    2. Annars, om ingen typargumentlista angavs och identifieraren matchar i exakt en importera namnet på ett namnområde med tillgängliga typer, refererar identifieraren till det namnområdet. Om ingen typargumentlista angavs och identifieraren matchar i mer än en import av namnet på ett namnområde med tillgängliga typer uppstår ett kompileringsfel.
    3. Annars, om importen innehåller en eller flera tillgängliga standardmoduler, och ett medlemsnamnsökning av identifieraren genererar en tillgänglig matchning i exakt en standardmodul, är resultatet exakt samma som en medlemsåtkomst i formuläret M.E(Of A), där M är standardmodulen som innehåller den matchande medlemmen, E är identifieraren och A är typargumentlistan. om det finns några. Om identifieraren matchar medlemmar av tillgänglig typ i mer än en standardmodul uppstår ett kompileringsfel.
  6. Om kompileringsmiljön definierar ett eller flera importalias och identifieraren matchar namnet på ett av dem refererar identifieraren till namnområdet eller typen. Om en typargumentlista anges uppstår ett kompileringsfel.

  7. Om kompileringsmiljön definierar en eller flera importer:

    1. Om identifieraren matchar i exakt en import av namnet på en tillgänglig typ med samma antal typparametrar som angavs i typargumentlistan, om någon, eller en typmedlem, refererar identifieraren till den typen eller typmedlemmen. Om identifieraren matchar i mer än en import av namnet på en tillgänglig typ med samma antal typparametrar som angavs i typargumentlistan, om någon, eller en typmedlem, uppstår ett kompileringsfel.
    2. Annars, om ingen typargumentlista angavs och identifieraren matchar i exakt en importera namnet på ett namnområde med tillgängliga typer, refererar identifieraren till det namnområdet. Om ingen typargumentlista angavs och identifieraren matchar i mer än en import av namnet på ett namnområde med tillgängliga typer uppstår ett kompileringsfel.
    3. Annars, om importen innehåller en eller flera tillgängliga standardmoduler, och ett medlemsnamnsökning av identifieraren genererar en tillgänglig matchning i exakt en standardmodul, är resultatet exakt samma som en medlemsåtkomst i formuläret M.E(Of A), där M är standardmodulen som innehåller den matchande medlemmen, E är identifieraren och A är typargumentlistan. om det finns några. Om identifieraren matchar medlemmar av tillgänglig typ i mer än en standardmodul uppstår ett kompileringsfel.
  8. I annat fall är namnet som anges av identifieraren odefinierat.

Ett enkelt namnuttryck som är odefinierat är ett kompileringsfel.

Normalt kan ett namn bara inträffa en gång i ett visst namnområde. Eftersom namnområden kan deklareras i flera .NET-sammansättningar är det dock möjligt att ha en situation där två sammansättningar definierar en typ med samma fullständigt kvalificerade namn. I så fall föredras en typ som deklarerats i den aktuella uppsättningen källfiler framför en typ som deklarerats i en extern .NET-sammansättning. Annars är namnet tvetydigt och det finns inget sätt att skilja namnet åt.

AddressOf-uttryck

Ett AddressOf uttryck används för att skapa en metodpekare. Uttrycket består av nyckelordet AddressOf och ett uttryck som måste klassificeras som en metodgrupp eller en sen åtkomst. Metodgruppen kan inte referera till konstruktorer.

Resultatet klassificeras som en metodpekare med samma associerade måluttryck och typargumentlista (om någon) som metodgruppen.

AddressOfExpression
    : 'AddressOf' Expression
    ;

Skriv uttryck

Ett typuttryck är ett GetType uttryck, ett TypeOf...Is uttryck, ett Is uttryck eller ett GetXmlNamespace uttryck.

TypeExpression
    : GetTypeExpression
    | TypeOfIsExpression
    | IsExpression
    | GetXmlNamespaceExpression
    ;

GetType-uttryck

Ett GetType uttryck består av nyckelordet GetType och namnet på en typ.

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*
    ;

Ett GetType uttryck klassificeras som ett värde och dess värde är den reflektionsklass (System.Type) som representerar dess GetTypeTypeName. Om GetTypeTypeName är en typparameter returnerar uttrycket objektet System.Type som motsvarar typargumentet som angavs för typparametern vid körning.

GetTypeTypeName är speciellt på två sätt:

  • Det är tillåtet att vara System.Void, den enda platsen på det språk där det här typnamnet kan refereras.

  • Det kan vara en konstruerad allmän typ med de typargument som utelämnas. På så GetType sätt kan uttrycket returnera det System.Type objekt som motsvarar själva den generiska typen.

I följande exempel visas uttrycket GetType :

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 resulterande utdata är:

Int32
Int32
String
Double[]

TypeOf... Är uttryck

Ett TypeOf...Is uttryck används för att kontrollera om körningstypen för ett värde är kompatibel med en viss typ. Den första operanden måste klassificeras som ett värde, får inte vara en omklassificerad lambda-metod och måste vara av en referenstyp eller en parametertyp av icke-tränad typ. Den andra operanden måste vara ett typnamn. Resultatet av uttrycket klassificeras som ett värde och är ett Boolean värde. Uttrycket utvärderas till True om körningstypen för operanden har en identitet, standard, referens, matris, värdetyp eller typparameterkonvertering till typen, False annars. Ett kompileringsfel inträffar om det inte finns någon konvertering mellan typen av uttryck och den specifika typen.

TypeOfIsExpression
    : 'TypeOf' Expression 'Is' LineTerminator? TypeName
    ;

Är uttryck

Ett Is eller IsNot -uttryck används för att göra en jämförelse av referensjämlikhet.

IsExpression
    : Expression 'Is' LineTerminator? Expression
    | Expression 'IsNot' LineTerminator? Expression
    ;

Varje uttryck måste klassificeras som ett värde och typen för varje uttryck måste vara en referenstyp, en parametertyp av ej tränad typ eller en nullbar värdetyp. Om typen av ett uttryck är en icke-tränad typparametertyp eller nullbar värdetyp måste dock det andra uttrycket vara literalen Nothing.

Resultatet klassificeras som ett värde och skrivs som Boolean. En Is åtgärd utvärderas till True om båda värdena refererar till samma instans eller båda värdena är Nothing, eller False på annat sätt. En IsNot åtgärd utvärderas till False om båda värdena refererar till samma instans eller båda värdena är Nothing, eller True på annat sätt.

GetXmlNamespace-uttryck

Ett GetXmlNamespace uttryck består av nyckelordet GetXmlNamespace och namnet på ett XML-namnområde som deklarerats av källfilen eller kompileringsmiljön.

GetXmlNamespaceExpression
    : 'GetXmlNamespace' OpenParenthesis XMLNamespaceName? CloseParenthesis
    ;

Ett GetXmlNamespace uttryck klassificeras som ett värde och dess värde är en instans av System.Xml.Linq.XNamespace som representerar XMLNamespaceName. Om den typen inte är tillgänglig uppstår ett kompileringsfel.

Till exempel:

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

Allt mellan parenteserna betraktas som en del av namnområdesnamnet, så XML-regler kring saker som blanksteg gäller. Till exempel:

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

XML-namnområdesuttrycket kan också utelämnas, i vilket fall uttrycket returnerar objektet som representerar standard-XML-namnområdet.

Medlemsåtkomstuttryck

Ett medlemsåtkomstuttryck används för att komma åt en medlem i en entitet.

MemberAccessExpression
    : MemberAccessBase? Period IdentifierOrKeyword
      ( OpenParenthesis 'Of' TypeArgumentList CloseParenthesis )?
    ;

MemberAccessBase
    : Expression
    | NonArrayTypeName
    | 'Global'
    | 'MyClass'
    | 'MyBase'
    ;

En medlemsåtkomst i formuläret , där E är ett uttryck, ett namn av typen icke-matris, nyckelordet Global, eller utelämnad och I är en identifierare med en valfri typargumentlista A, utvärderas och klassificeras enligt E.I(Of A)följande:

  1. Om E utelämnas ersätts uttrycket från den omedelbart innehållande With instruktionen och E medlemsåtkomsten utförs. Om det inte finns någon innehållande With instruktion uppstår ett kompileringsfel.

  2. Om E klassificeras som ett namnområde eller E är nyckelordet Globalgörs medlemssökningen i kontexten för det angivna namnområdet. Om I är namnet på en tillgänglig medlem i namnområdet med samma antal typparametrar som angavs i typargumentlistan, om någon, så blir resultatet den medlemmen. Resultatet klassificeras som ett namnområde eller en typ beroende på medlem. Annars uppstår ett kompileringsfel.

  3. Om E är en typ eller ett uttryck som klassificeras som en typ görs medlemssökningen i kontexten för den angivna typen. Om I är namnet på en tillgänglig medlem i EE.I utvärderas och klassificeras följande:

    1. Om I är nyckelordet New och E inte är en uppräkning uppstår ett kompileringsfel.
    2. Om I identifierar en typ med samma antal typparametrar som angavs i typargumentlistan, om någon, blir resultatet den typen.
    3. Om I identifierar en eller flera metoder är resultatet en metodgrupp med den associerade typargumentlistan och inget associerat måluttryck.
    4. Om I identifierar en eller flera egenskaper och ingen typargumentlista angavs är resultatet en egenskapsgrupp utan associerat måluttryck.
    5. Om I identifierar en delad variabel och ingen typargumentlista angavs blir resultatet antingen en variabel eller ett värde. Om variabeln är skrivskyddad och referensen inträffar utanför den delade konstruktorn för den typ där variabeln deklareras, blir resultatet värdet för den delade variabeln I i E. Annars är resultatet den delade variabeln I i E.
    6. Om I identifierar en delad händelse och ingen typargumentlista angavs är resultatet en händelseåtkomst utan associerat måluttryck.
    7. Om I identifierar en konstant och ingen typargumentlista angavs blir resultatet värdet för den konstanten.
    8. Om I identifierar en uppräkningsmedlem och ingen typargumentlista angavs är resultatet värdet för den uppräkningsmedlemmen.
    9. Annars är E.I en ogiltig medlemsreferens och ett kompileringsfel inträffar.
  4. Om E klassificeras som en variabel eller ett värde, vars typ är T, görs medlemssökningen i kontexten T. Om I är namnet på en tillgänglig medlem i TE.I utvärderas och klassificeras följande:

    1. Om I är nyckelordet New, E är Me, MyBase, eller MyClass, och inga typargument angavs, är resultatet en metodgrupp som representerar instanskonstruktorerna av typen med E ett associerat måluttryck av och ingen typargumentlista E . Annars uppstår ett kompileringsfel.
    2. Om I identifierar en eller flera metoder, inklusive tilläggsmetoder om T inte Object, är resultatet en metodgrupp med den associerade typargumentlistan och ett associerat måluttryck för E.
    3. Om I identifierar en eller flera egenskaper och inga typargument har angetts är resultatet en egenskapsgrupp med ett associerat måluttryck av E.
    4. Om I identifierar en delad variabel eller en instansvariabel och inga typargument har angetts är resultatet antingen en variabel eller ett värde. Om variabeln är skrivskyddad och referensen inträffar utanför en konstruktor för klassen där variabeln deklareras lämplig för typen av variabel (delad eller instans), blir resultatet värdet för variabeln I i objektet som refereras av E. Om T är en referenstyp blir resultatet variabeln I i objektet som refereras av E. Annars, om T är en värdetyp och uttrycket E klassificeras som en variabel, är resultatet en variabel. Annars är resultatet ett värde.
    5. Om I identifierar en händelse och inga typargument har angetts är resultatet en händelseåtkomst med ett associerat måluttryck av E.
    6. Om I identifierar en konstant och inga typargument angavs är resultatet värdet för den konstanten.
    7. Om I identifierar en uppräkningsmedlem och inga typargument har angetts är resultatet värdet för den uppräkningsmedlemmen.
    8. Om T är Objectär resultatet ett sent bundet medlemsuppslag klassificerat som en sen bunden åtkomst med den associerade typargumentlistan och ett associerat måluttryck för E.
  5. Annars är E.I en ogiltig medlemsreferens och ett kompileringsfel inträffar.

En medlemsåtkomst i formuläret MyClass.I(Of A) motsvarar Me.I(Of A), men alla medlemmar som nås på det behandlas som om medlemmarna inte är åsidosättningsbara. Den medlem som används påverkas därför inte av körningstypen för det värde som medlemmen används till.

En medlemsåtkomst i formuläret MyBase.I(Of A) motsvarar CType(Me, T).I(Of A) var T är den direkta bastypen för den typ som innehåller medlemsåtkomstuttrycket. Alla metodanrop på den behandlas som om metoden som anropas inte kan åsidosättas. Den här typen av medlemsåtkomst kallas även för basåtkomst.

I följande exempel visas hur Me, MyBase och MyClass relaterar:

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

Den här koden skriver ut:

MoreDerived.F
Derived.F
Derived.F

När ett medlemsåtkomstuttryck börjar med nyckelordet Globalrepresenterar nyckelordet det yttre namnområdet som inte är namngivet, vilket är användbart i situationer där en deklaration skuggar ett omslutande namnområde. Nyckelordet Global tillåter "escapeing" ut till det yttersta namnområdet i den situationen. Till exempel:

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

I exemplet ovan är det första metodanropet ogiltigt eftersom identifieraren System binder till klassen System, inte namnområdet System. Det enda sättet att komma åt System namnområdet är att använda Global för att fly ut till det yttersta namnområdet.

Om medlemmen som används delas är alla uttryck till vänster i perioden överflödiga och utvärderas inte om inte medlemsåtkomsten görs sent bunden. Tänk till exempel på följande kod:

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

Den skrivs The value of F is: 10 ut eftersom funktionen ReturnC inte behöver anropas för att tillhandahålla en instans av C för att få åtkomst till den delade medlemmen F.

Identisk typ och medlemsnamn

Det är inte ovanligt att namnge medlemmar med samma namn som deras typ. I den situationen kan dock olämpligt namn döljas:

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

I föregående exempel binder det enkla namnet Color i DefaultColor till instansegenskapen i stället för typen. Eftersom det inte går att referera till en instansmedlem i en delad medlem är detta normalt ett fel.

En särskild regel ger dock åtkomst till typen i det här fallet. Om basuttrycket för ett medlemsåtkomstuttryck är ett enkelt namn och binder till en konstant, fält, egenskap, lokal variabel eller parameter vars typ har samma namn, kan basuttrycket referera till antingen medlemmen eller typen. Detta kan aldrig resultera i tvetydighet eftersom de medlemmar som kan nås av någon av dem är desamma.

Standardinstanser

I vissa situationer har klasser som härletts från en vanlig basklass vanligtvis eller alltid bara en enda instans. De flesta fönster som visas i ett användargränssnitt har till exempel bara en instans som visas på skärmen när som helst. För att förenkla arbetet med dessa typer av klasser kan Visual Basic automatiskt generera standardinstanser av klasserna som tillhandahåller en enda, lätt refererad instans för varje klass.

Standardinstanser skapas alltid för en familj av typer i stället för för en viss typ. I stället för att skapa en standardinstans för en klass Form1 som härleds från formulär skapas standardinstanser för alla klasser som härletts från formulär. Det innebär att varje enskild klass som härleds från basklassen inte behöver markeras särskilt för att ha en standardinstans.

Standardinstansen av en klass representeras av en kompilatorgenererad egenskap som returnerar standardinstansen av den klassen. Egenskapen som genereras som medlem i en klass som kallas gruppklassen som hanterar allokering och förstör standardinstanser för alla klasser som härleds från den specifika basklassen. Till exempel kan alla standardinstansegenskaper för klasser som härleds från Form samlas in i MyForms klassen. Om en instans av gruppklassen returneras av uttrycket My.Formskommer följande kod åt standardinstanserna av härledda klasser Form1 och 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

Standardinstanser skapas inte förrän den första referensen till dem. Om du hämtar egenskapen som representerar standardinstansen skapas standardinstansen om den inte redan har skapats eller har angetts till Nothing. Om du vill tillåta testning av förekomsten av en standardinstans skapas inte standardinstansen när en standardinstans är målet för en Is eller-operatorn IsNot . Därför är det möjligt att testa om en standardinstans är Nothing eller någon annan referens utan att orsaka att standardinstansen skapas.

Standardinstanser är avsedda att göra det enkelt att referera till standardinstansen utanför klassen som har standardinstansen. Om du använder en standardinstans inifrån en klass som definierar den kan det orsaka förvirring om vilken instans som hänvisas till, dvs. standardinstansen eller den aktuella instansen. Följande kod ändrar till exempel endast värdet x i standardinstansen, även om den anropas från en annan instans. Därför skulle koden skriva ut värdet 5 i stället för 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

För att förhindra den här typen av förvirring är det inte giltigt att referera till en standardinstans inifrån en instansmetod av standardinstanstypen.

Standardinstanser och typnamn

En standardinstans kan också vara tillgänglig direkt via dess typs namn. I det här fallet ändras i alla uttryckskontexter där typnamnet inte tillåts uttrycket E, där E representerar det fullständigt kvalificerade namnet på klassen med en standardinstans, till E', där E' representerar ett uttryck som hämtar standardinstansegenskapen. Om standardinstanser för klasser som härletts från Form tillåter åtkomst till standardinstansen via typnamnet motsvarar följande kod koden i föregående exempel:

Module Main
    Sub Main()
        Form1.x = 10
        Console.WriteLine(Form2.y)
    End Sub
End Module

Det innebär också att en standardinstans som är tillgänglig via dess typs namn också kan tilldelas via typnamnet. Följande kod anger till exempel standardinstansen av Form1 till Nothing:

Module Main
    Sub Main()
        Form1 = Nothing
    End Sub
End Module

Observera att innebörden av E.I var E representerar en klass och I representerar en delad medlem ändras inte. Ett sådant uttryck kommer fortfarande åt den delade medlemmen direkt från klassinstansen och refererar inte till standardinstansen.

Gruppklasser

Attributet Microsoft.VisualBasic.MyGroupCollectionAttribute anger gruppklassen för en familj med standardinstanser. Attributet har fyra parametrar:

  • Parametern TypeToCollect anger basklassen för gruppen. Alla instanserbara klasser utan parametrar av öppen typ som härleds från en typ med det här namnet (oavsett typparametrar) har automatiskt en standardinstans.

  • Parametern CreateInstanceMethodName anger vilken metod som ska anropas i gruppklassen för att skapa en ny instans i en standardinstansegenskap.

  • Parametern DisposeInstanceMethodName anger vilken metod som ska anropas i gruppklassen för att ta bort en standardinstansegenskap om standardinstansegenskapen tilldelas värdet Nothing.

  • Parametern DefaultInstanceAlias anger vilket uttryck E' som ska ersätta klassnamnet om standardinstanserna är tillgängliga direkt via deras typnamn. Om den här parametern är Nothing eller en tom sträng är standardinstanser av den här grupptypen inte tillgängliga direkt via deras typs namn. (Obs! I alla aktuella implementeringar av språket Visual Basic ignoreras parametern DefaultInstanceAlias , förutom i kod som tillhandahålls av kompilatorn.)

Flera typer kan samlas in i samma grupp genom att avgränsa namnen på typerna och metoderna i de tre första parametrarna med kommatecken. Det måste finnas samma antal objekt i varje parameter och listelementen matchas i ordning. Följande attributdeklaration samlar till exempel in typer som härleds från C1eller C2C3 till en enda grupp:

<Microsoft.VisualBasic.MyGroupCollection("C1, C2, C3", _
    "CreateC1, CreateC2, CreateC3", _
    "DisposeC1, DisposeC2, DisposeC3", "My.Cs")>
Public NotInheritable Class MyCs
    ...
End Class

Signaturen för create-metoden måste vara i formuläret Shared Function <Name>(Of T As {New, <Type>})(Instance Of T) As T. Metoden för bortskaffning måste vara av formatet Shared Sub <Name>(Of T As <Type>)(ByRef Instance Of T). Gruppklassen för exemplet i föregående avsnitt kan därför deklareras på följande sätt:

<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

Om en källfil deklarerade en härledd klass Form1skulle den genererade gruppklassen motsvara:

<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

Tilläggsmetodsamling

Tilläggsmetoder för medlemsåtkomstuttrycket E.I samlas in genom att alla tilläggsmetoder samlas in med det namn I som är tillgängligt i den aktuella kontexten:

  1. Först kontrolleras varje kapslad typ som innehåller uttrycket, från den innersta och går till den yttersta.
  2. Sedan kontrolleras varje kapslad namnrymd, från den innersta och går till det yttersta namnområdet.
  3. Sedan kontrolleras importerna i källfilen.
  4. Sedan kontrolleras de importer som definierats av kompileringsmiljön.

En tilläggsmetod samlas bara in om det finns en bredare intern konvertering från måluttryckstypen till typen av den första parametern i tilläggsmetoden. Och till skillnad från vanlig bindning av enkla namnuttryck samlar sökningen in alla tilläggsmetoder. -samlingen stoppas inte när en tilläggsmetod hittas. Till exempel:

Imports System.Runtime.CompilerServices

Class C1
End Class


Namespace N1
    Module N1C1Extensions
        <Extension> _
        Sub M1(c As C1, x As Integer)
        End Sub
    End Module
End Namespace

Namespace N1.N2
    Module N2C1Extensions
        <Extension> _
        Sub M1(c As C1, y As 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

I det här exemplet, även om N2C1Extensions.M1 det finns före N1C1Extensions.M1, betraktas båda som tilläggsmetoder. När alla förlängningsmetoder har samlats in blir de sedan curryade. Currying tar målet för tilläggsmetodanropet och tillämpar det på tilläggsmetodanropet, vilket resulterar i en ny metodsignatur med den första parametern borttagen (eftersom den har angetts). Till exempel:

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

I exemplet ovan är resultatet av att tillämpa vExt1.M på metoden signatur Sub M(y As Integer).

Förutom att ta bort den första parametern i tilläggsmetoden tar currying även bort alla metodtypsparametrar som är en del av typen av den första parametern. När du använder en tilläggsmetod med en metodtypsparameter tillämpas typinferens på den första parametern och resultatet korrigeras för alla typparametrar som härleds. Om typinferensen misslyckas ignoreras metoden. Till exempel:

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

I exemplet ovan är resultatet av att tillämpa vExt1.M på metoden signatur Sub M(Of U)(y As U), eftersom typparametern T härleds som ett resultat av currying och är nu fast. Eftersom typparametern U inte härleddes som en del av curryingen förblir den en öppen parameter. På samma sätt, eftersom typparametern T härleds som ett resultat av att Ext2.Mtillämpa v på , blir typen av parameter y fast som Integer. Det kommer inte att härledas till någon annan typ. När signaturen hämtas tillämpas även alla begränsningar förutom New begränsningar. Om begränsningarna inte uppfylls, eller är beroende av en typ som inte har härledts som en del av currying, ignoreras tilläggsmetoden. Till exempel:

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

Observera. En av de främsta orsakerna till att tilläggsmetoder används är att det gör att frågeuttryck kan härleda typen av iteration innan argumenten utvärderas till en frågemönstermetod. Eftersom de flesta frågemönstermetoder använder lambda-uttryck, vilket kräver själva typinferensen, förenklar detta avsevärt processen för att utvärdera ett frågeuttryck.

Till skillnad från normalt gränssnittsarv är tilläggsmetoder som utökar två gränssnitt som inte är relaterade till varandra tillgängliga, så länge de inte har samma currysignatur:

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

Slutligen är det viktigt att komma ihåg att tilläggsmetoder inte beaktas när du utför sen bindning:

Module Test
    Sub Main()
        Dim o As Object = ...

        ' Ignores extension methods
        o.M1()
    End Sub
End Module

Ordlistemedlemsåtkomstuttryck

Ett ordlistemedlemsåtkomstuttryck används för att leta upp en medlem i en samling. En ordlistemedlemsåtkomst har formen E!I, där E är ett uttryck som klassificeras som ett värde och I är en identifierare.

DictionaryAccessExpression
    : Expression? '!' IdentifierOrKeyword
    ;

Uttryckets typ måste ha en standardegenskap indexerad med en enda String parameter. Ordlistans medlemsåtkomstuttryck E!I omvandlas till uttrycket E.D("I"), där D är standardegenskapen Eför . Till exempel:

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

Om ett utropstecken anges utan uttryck antas uttrycket från den omedelbart innehållande With instruktionen. Om det inte finns någon innehållande With instruktion uppstår ett kompileringsfel.

Anropsuttryck

Ett anropsuttryck består av ett anropsmål och en valfri argumentlista.

InvocationExpression
    : Expression ( OpenParenthesis ArgumentList? CloseParenthesis )?
    ;

ArgumentList
    : PositionalArgumentList
    | PositionalArgumentList Comma NamedArgumentList
    | NamedArgumentList
    ;

PositionalArgumentList
    : Expression? ( Comma Expression? )*
    ;

NamedArgumentList
    : IdentifierOrKeyword ColonEquals Expression
      ( Comma IdentifierOrKeyword ColonEquals Expression )*
    ;

Måluttrycket måste klassificeras som en metodgrupp eller ett värde vars typ är en ombudstyp. Om måluttrycket är ett värde vars typ är en ombudstyp blir målet för anropsuttrycket metodgruppen för Invoke medlemmen av delegattypen och måluttrycket blir det associerade måluttrycket för metodgruppen.

En argumentlista har två avsnitt: positionsargument och namngivna argument. Positionsargument är uttryck och måste föregå namngivna argument. Namngivna argument börjar med en identifierare som kan matcha nyckelord, följt av := och ett uttryck.

Om metodgruppen bara innehåller en tillgänglig metod, inklusive både instans- och tilläggsmetoder, och den metoden inte tar några argument och är en funktion, tolkas metodgruppen som ett anropsuttryck med en tom argumentlista och resultatet används som mål för ett anropsuttryck med de angivna argumentistorna. Till exempel:

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

Annars tillämpas överbelastningsmatchning på metoderna för att välja den mest tillämpliga metoden för de angivna argumentistor. Om den mest tillämpliga metoden är en funktion klassificeras resultatet av anropsuttrycket som ett värde som anges som funktionens returtyp. Om den mest tillämpliga metoden är en subrutin klassificeras resultatet som void. Om den mest tillämpliga metoden är en partiell metod som inte har någon brödtext ignoreras anropsuttrycket och resultatet klassificeras som void.

För ett tidigt bundet anropsuttryck utvärderas argumenten i den ordning motsvarande parametrar deklareras i målmetoden. För ett sent bundet medlemsåtkomstuttryck utvärderas de i den ordning de visas i medlemsåtkomstuttrycket: se Avsnitt Late-Bound Uttryck.

Lösning för överbelastad metod:

För överbelastningsmatchning, specificitet för medlemmar/typer med tanke på en argumentlista, genericity, tillämplighet till argumentlista, skicka argument och plockargument för valfria parametrar, villkorsstyrda metoder och typargumentinferens: se Avsnittet Överbelastningsmatchning.

Indexuttryck

Ett indexuttryck resulterar i ett matriselement eller omklassificerar en egenskapsgrupp till en egenskapsåtkomst. Ett indexuttryck består i ordning av ett uttryck, en inledande parentes, en indexargumentlista och en avslutande parentes.

IndexExpression
    : Expression OpenParenthesis ArgumentList? CloseParenthesis
    ;

Indexuttryckets mål måste klassificeras som antingen en egenskapsgrupp eller ett värde. Ett indexuttryck bearbetas på följande sätt:

  • Om måluttrycket klassificeras som ett värde och dess typ inte är en matristyp, Object, eller System.Array, måste typen ha en standardegenskap. Indexet utförs på en egenskapsgrupp som representerar alla standardegenskaper för typen. Även om det inte är giltigt att deklarera en parameterlös standardegenskap i Visual Basic kan andra språk tillåta att en sådan egenskap deklareras. Därför tillåts indexering av en egenskap utan argument.

  • Om uttrycket resulterar i ett värde av en matristyp måste antalet argument i argumentlistan vara samma som matristypens rangordning och får inte innehålla namngivna argument. Om något av indexen är ogiltigt vid körningen utlöses ett System.IndexOutOfRangeException undantag. Varje uttryck måste vara implicit konvertibelt för att kunna skriva Integer. Resultatet av indexuttrycket är variabeln i det angivna indexet och klassificeras som en variabel.

  • Om uttrycket klassificeras som en egenskapsgrupp används överbelastningsmatchning för att avgöra om någon av egenskaperna gäller för indexargumentlistan. Om egenskapsgruppen bara innehåller en egenskap som har en Get accessor och om den accessorn inte tar några argument tolkas egenskapsgruppen som ett indexuttryck med en tom argumentlista. Resultatet används som mål för det aktuella indexuttrycket. Om inga egenskaper är tillämpliga uppstår ett kompileringsfel. Annars resulterar uttrycket i en egenskapsåtkomst med det associerade måluttrycket (om något) för egenskapsgruppen.

  • Om uttrycket klassificeras som en sen bunden egenskapsgrupp eller som ett värde vars typ är Object eller System.Array, skjuts bearbetningen av indexuttrycket upp till körningstiden och indexeringen är sen bunden. Uttrycket resulterar i en sent bunden egenskapsåtkomst som skrivs som Object. Det associerade måluttrycket är antingen måluttrycket, om det är ett värde eller det associerade måluttrycket för egenskapsgruppen. Vid körning bearbetas uttrycket på följande sätt:

  • Om uttrycket klassificeras som en sen bunden egenskapsgrupp kan uttrycket resultera i en metodgrupp, en egenskapsgrupp eller ett värde (om medlemmen är en instans eller delad variabel). Om resultatet är en metodgrupp eller egenskapsgrupp tillämpas överbelastningsmatchning på gruppen för att fastställa rätt metod för argumentlistan. Om överbelastningsupplösningen misslyckas utlöses ett System.Reflection.AmbiguousMatchException undantag. Resultatet bearbetas antingen som en egenskapsåtkomst eller som ett anrop och resultatet returneras. Om anropet är av en subrutin blir Nothingresultatet .

  • Om körningstypen för måluttrycket är en matristyp eller System.Arrayär resultatet av indexuttrycket värdet för variabeln i det angivna indexet.

  • Annars måste körningstypen för uttrycket ha en standardegenskap och indexet utförs på den egenskapsgrupp som representerar alla standardegenskaper för typen. Om typen inte har någon standardegenskap genereras ett System.MissingMemberException undantag.

Nya uttryck

Operatorn New används för att skapa nya instanser av typer. Det finns fyra uttrycksformer New :

  • Uttryck för att skapa objekt används för att skapa nya instanser av klasstyper och värdetyper.

  • Matrisskapande uttryck används för att skapa nya instanser av matristyper.

  • Uttryck för att skapa ombud (som inte har någon distinkt syntax från uttryck för att skapa objekt) används för att skapa nya instanser av ombudstyper.

  • Anonyma objektskapande uttryck används för att skapa nya instanser av anonyma klasstyper.

NewExpression
    : ObjectCreationExpression
    | ArrayExpression
    | AnonymousObjectCreationExpression
    ;

Ett New uttryck klassificeras som ett värde och resultatet är den nya instansen av typen.

Object-Creation uttryck

Ett uttryck för att skapa objekt används för att skapa en ny instans av en klasstyp eller en strukturtyp.

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
    ;

Typen av ett objektskapandeuttryck måste vara en klasstyp, en strukturtyp eller en typparameter med en New begränsning och får inte vara en MustInherit klass. Givet ett uttryck för att skapa objekt i formuläret New T(A), där T är en klasstyp eller strukturtyp och A är en valfri argumentlista, avgör överlagringsmatchning rätt konstruktor T för att anropa. En typparameter med en New begränsning anses ha en enda, parameterlös konstruktor. Om ingen konstruktor är anropsbar uppstår ett kompileringsfel. annars resulterar uttrycket i skapandet av en ny instans av T att använda den valda konstruktorn. Om det inte finns några argument kan parenteserna utelämnas.

Var en instans allokeras beror på om instansen är en klasstyp eller en värdetyp. New instanser av klasstyper skapas på systemhögen, medan nya instanser av värdetyper skapas direkt på stacken.

Ett uttryck för att skapa objekt kan också ange en lista över medlemsinitierare efter konstruktorargumenten. Dessa medlemsinitierare är prefix med nyckelordet Withoch initialiserarlistan tolkas som om den vore i kontexten för en With -instruktion. Till exempel, med tanke på klassen:

Class Customer
    Dim Name As String
    Dim Address As String
End Class

Koden:

Module Test
    Sub Main()
        Dim x As New Customer() With { .Name = "Bob Smith", _
            .Address = "123 Main St." }
    End Sub
End Module

Motsvarar ungefär:

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

Varje initierare måste ange ett namn som ska tilldelas och namnet måste vara en variabel eller egenskap som inteReadOnly är en instans av den typ som skapas. Medlemsåtkomsten kommer inte att vara senbunden om typen som skapas är Object. Initiatorer kanske inte använder nyckelordet Key . Varje medlem i en typ kan bara initieras en gång. Initialiseraruttrycken kan dock referera till varandra. Till exempel:

Module Test
    Sub Main()
        Dim x As New Customer() With { .Name = "Bob Smith", _
            .Address = .Name & " St." }
    End Sub
End Module

Initieringarna tilldelas från vänster till höger, så om en initialiserare refererar till en medlem som inte har initierats ännu ser den det värde som instansvariabeln har när konstruktorn har kört:

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

Initierare kan kapslas:

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

Om typen som skapas är en samlingstyp och har en instansmetod med namnet Add (inklusive tilläggsmetoder och delade metoder) kan uttrycket för att skapa objekt ange en initieringsprefix för samlingen med nyckelordet From. Ett uttryck för att skapa objekt kan inte ange både en medlemsinitierare och en insamlingsinitierare. Varje element i insamlingsinitiatorn skickas som ett argument till en anrop av Add funktionen. Till exempel:

Dim list = New List(Of Integer)() From { 1, 2, 3, 4 }

är motsvarande:

Dim list = New List(Of Integer)()
list.Add(1)
list.Add(2)
list.Add(3)

Om ett element är en samlingsinitiator skickas varje element i undersamlingsinitiatorn som ett enskilt argument till Add funktionen. Till exempel följande:

Dim dict = Dictionary(Of Integer, String) From { { 1, "One" },{ 2, "Two" } }

är motsvarande:

Dim dict = New Dictionary(Of Integer, String)
dict.Add(1, "One")
dict.Add(2, "Two")

Denna expansion är alltid klar och görs bara en nivå djup; därefter betraktas underinitierare som matrisliteraler. Till exempel:

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

Matrisuttryck

Ett matrisuttryck används för att skapa en ny instans av en matristyp. Det finns två typer av matrisuttryck: skapandeuttryck för matriser och matrisliteraler.

Uttryck för skapande av matris

Om en matrisstorleksinitieringsmodifierare anges härleds den resulterande matristypen genom att ta bort vart och ett av de enskilda argumenten från argumentlistan för initiering av matrisstorlek. Värdet för varje argument avgör den övre gränsen för motsvarande dimension i den nyligen allokerade matrisinstansen. Om uttrycket har en initiator för en icke-tom samling måste varje argument i argumentlistan vara en konstant, och de rangordnings- och dimensionslängder som anges i uttryckslistan måste överensstämma med initieringsobjektet för samlingen.

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 }

Om en initieringsmodifierare för matrisstorlek inte anges måste typnamnet vara en matristyp och insamlingsinitieraren måste vara tom eller ha samma antal kapslingsnivåer som rangordningen för den angivna matristypen. Alla element på den innersta kapslingsnivån måste implicit konverteras till matrisens elementtyp och måste klassificeras som ett värde. Antalet element i varje kapslad insamlingsinitiator måste alltid vara konsekvent med storleken på de andra samlingarna på samma nivå. De enskilda dimensionslängderna härleds från antalet element i var och en av motsvarande kapslingsnivåer i insamlingsinitiatorn. Om insamlingsinitiatorn är tom är längden på varje dimension noll.

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 } }

Den yttersta kapslingsnivån för en samlingsinitierare motsvarar den vänstra dimensionen för en matris, och den innersta kapslingsnivån motsvarar den högra dimensionen. Exemplet:

Dim array As Integer(,) = _
    { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }, { 8, 9 } }

Motsvarar följande:

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

Om insamlingsinitiatorn är tom (dvs. en som innehåller klammerparenteser men ingen initialiserarlista) och gränserna för dimensionerna för matrisen som initieras är kända, representerar den tomma insamlingsinitiatorn en matrisinstans av den angivna storleken där alla element har initierats till elementtypens standardvärde. Om gränserna för dimensionerna för matrisen som initieras inte är kända representerar den tomma insamlingsinitiatorn en matrisinstans där alla dimensioner är storlek noll.

En matrisinstans rangordning och längd för varje dimension är konstanta under hela instansens livslängd. Med andra ord går det inte att ändra rangordningen för en befintlig matrisinstans och det går inte heller att ändra storlek på dess dimensioner.

Matrisliteraler

En matrisliteral anger en matris vars elementtyp, rangordning och gränser härleds från en kombination av uttryckskontexten och en samlingsinitierare. Detta förklaras i Omklassificering av avsnittsuttryck.

ArrayExpression
    : ArrayCreationExpression
    | ArrayLiteralExpression
    ;

ArrayCreationExpression
    : 'New' NonArrayTypeName ArrayNameModifier CollectionInitializer
    ;

ArrayLiteralExpression
    : CollectionInitializer
    ;

Till exempel:

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

Formatet och kraven för insamlingsinitieraren i en matrisliteral är exakt samma som för insamlingsinitieraren i ett uttryck för att skapa matriser.

Observera. En matrisliteral skapar inte matrisen i sig själv. I stället är det omklassificeringen av uttrycket till ett värde som gör att matrisen skapas. Konverteringen CType(new Integer() {1,2,3}, Short()) är till exempel inte möjlig eftersom det inte finns någon konvertering från Integer() till Short(), men uttrycket CType({1,2,3},Short()) är möjligt eftersom det först omklassificerar matrisliteralen till matrisens skapandeuttryck New Short() {1,2,3}.

Delegate-Creation uttryck

Ett uttryck för att skapa ombud används för att skapa en ny instans av en ombudstyp. Argumentet för ett uttryck för att skapa ombud måste vara ett uttryck som klassificeras som en metodpekare eller en lambda-metod.

Om argumentet är en metodpekare måste en av metoderna som refereras av metodpekaren gälla för signaturen för ombudstypen. En metod M gäller för en ombudstyp D om:

  • M är inte Partial eller har en kropp.

  • Både M och D är funktioner, eller D är en underrutin.

  • M och D har samma antal parametrar.

  • Parametertyperna för M var och en har en konvertering från typen av motsvarande parametertyp , Doch deras modifierare (dvs. ByRef, ByVal) matchar.

  • Returtypen M, om någon, har en konvertering till returtypen D.

Om metodpekaren refererar till en sen bunden åtkomst antas den sena åtkomsten vara till en funktion som har samma antal parametrar som ombudstypen.

Om strikt semantik inte används och det bara finns en metod som refereras av metodpekaren, men den inte är tillämplig på grund av att den inte har några parametrar och ombudstypen gör det, anses metoden vara tillämplig och parametrarna eller returvärdet ignoreras helt enkelt. Till exempel:

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

Observera. Denna avkoppling tillåts endast när strikta semantik inte används på grund av tilläggsmetoder. Eftersom tilläggsmetoder endast beaktas om en vanlig metod inte var tillämplig är det möjligt för en instansmetod utan parametrar att dölja en tilläggsmetod med parametrar i syfte att delegera konstruktion.

Om fler än en metod som refereras till av metodpekaren gäller för ombudstypen används överlagringsmatchning för att välja mellan kandidatmetoderna. Typerna av parametrar till ombudet används som typer av argument för överbelastningsmatchning. Om ingen metodkandidat är mest tillämplig uppstår ett kompileringsfel. I följande exempel initieras den lokala variabeln med ett ombud som refererar till den andra Square metoden eftersom den metoden är mer tillämplig för signaturen och returtypen DoubleFuncför .

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

Om den andra Square metoden inte hade funnits skulle den första Square metoden ha valts. Om strikt semantik anges av kompileringsmiljön eller av Option Strictuppstår ett kompileringsfel om den mest specifika metoden som refereras av metodpekaren är smalare än ombudets signatur. En metod M anses vara smalare än en ombudstyp D om:

  • En parametertyp av M har en bredare konvertering till motsvarande parametertyp D.

  • Eller så har returtypen, om någon, M en begränsad konvertering till returtypen D.

Om typargument är associerade med metodpekaren beaktas endast metoder med samma antal typargument. Om inga typargument är associerade med metodpekaren används typinferens vid matchning av signaturer mot en allmän metod. Till skillnad från annan normal typinferens används returtypen för ombudet vid slutsatsdragning av typargument, men returtyper beaktas fortfarande inte vid fastställandet av den minst allmänna överbelastningen. I följande exempel visas båda sätten att ange ett typargument till ett uttryck för att skapa ombud:

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

I exemplet ovan instansierades en icke-generisk delegattyp med hjälp av en allmän metod. Det går också att skapa en instans av en konstruerad ombudstyp med hjälp av en allmän metod. Till exempel:

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

Om argumentet för uttrycket för att skapa ombud är en lambda-metod måste lambda-metoden tillämpas på signaturen för ombudstypen. En lambda-metod L gäller för en ombudstyp D om:

  • Om L har parametrar, D har samma antal parametrar. (Om L det inte finns några parametrar ignoreras parametrarna D för.)

  • Parametertyperna för L var och en har en konvertering till typen av motsvarande parametertyp , Doch deras modifierare (dvs. ByRef, ByVal) matchar.

  • Om D är en funktion har returtypen L en konvertering till returtypen D. (Om D är en underrutin ignoreras returvärdet L för.)

Om parametertypen för en parameter L utelämnas, härleds typen av motsvarande parameter i D . Om parametern L för har matris- eller null-namnmodifierare returneras ett kompileringsfel. När alla parametertyper L är tillgängliga härleds typen av uttryck i lambda-metoden. Till exempel:

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

I vissa situationer där ombudssignaturen inte exakt matchar lambda-metoden eller metodsignaturen kanske .NET Framework inte stöder skapandet av ombud internt. I så fall används ett lambda-metoduttryck för att matcha de två metoderna. Till exempel:

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

Resultatet av ett uttryck för att skapa ombud är en delegatinstans som refererar till matchningsmetoden med det associerade måluttrycket (om det finns) från metodpekaruttrycket. Om måluttrycket skrivs som en värdetyp kopieras värdetypen till systemhuppen eftersom ett ombud bara kan peka på en metod för ett objekt i heapen. Metoden och objektet som ett ombud refererar till förblir konstant under hela livslängden för ombudet. Med andra ord går det inte att ändra målet eller objektet för ett ombud när det har skapats.

Anonyma Object-Creation uttryck

Ett uttryck för att skapa objekt med medlemsinitierare kan också utelämna typnamnet helt.

AnonymousObjectCreationExpression
    : 'New' ObjectMemberInitializer
    ;

I så fall skapas en anonym typ baserat på de typer och namn på medlemmar som initieras som en del av uttrycket. Till exempel:

Module Test
    Sub Main()
        Dim Customer = New With { .Name = "John Smith", .Age = 34 }

        Console.WriteLine(Customer.Name)
    End Sub
End Module

Typen som skapas av ett anonymt objektskapandeuttryck är en klass som inte har något namn, ärver direkt från Objectoch har en uppsättning egenskaper med samma namn som de medlemmar som tilldelats i medlemsinitierarens lista. Typen av varje egenskap härleds med samma regler som inferens för lokal variabeltyp. Genererade anonyma typer åsidosätter ToStringockså och returnerar en strängrepresentation av alla medlemmar och deras värden. (Det exakta formatet för den här strängen ligger utanför den här specifikationens omfång).

Som standard är egenskaperna som genereras av den anonyma typen skrivskyddade. Det går att markera en anonym typegenskap som skrivskyddad med hjälp Key av modifieraren. Modifieraren Key anger att fältet kan användas för att unikt identifiera värdet som den anonyma typen representerar. Förutom att göra egenskapen skrivskyddad gör den även att den anonyma typen åsidosätter Equals och GetHashCode implementerar gränssnittet System.IEquatable(Of T) (fyller i anonym typ för T). Medlemmarna definieras på följande sätt:

Function Equals(obj As Object) As Booleanoch Function Equals(val As T) As Boolean implementeras genom att verifiera att de två instanserna är av samma typ och sedan jämföra varje Key medlem med .Object.Equals Om alla Key medlemmar är lika returnerar returnerar EqualsTrueannars EqualsFalse.

Function GetHashCode() As Integer implementeras så att om Equals är sant för två instanser av den anonyma typen returnerar samma GetHashCode värde. Hashen börjar med ett seed-värde och multiplicerar sedan hashvärdet med 31 för varje Key medlem och lägger till Key medlemmens hashvärde (tillhandahålls av GetHashCode) om medlemmen inte är en referenstyp eller nullbar värdetyp med värdet Nothing.

Till exempel den typ som skapades i -instruktionen:

Dim zipState = New With { Key .ZipCode = 98112, .State = "WA" }

skapar en klass som ser ungefär så här ut (även om den exakta implementeringen kan variera):

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

För att förenkla situationen där en anonym typ skapas från fält av en annan typ kan fältnamn härledas direkt från uttryck i följande fall:

  • Ett enkelt namnuttryck x härleder namnet x.

  • Ett medlemsåtkomstuttryck x.y härleder namnet y.

  • Ett ordlisteuppslagsuttryck x!y härleder namnet y.

  • Ett anrops- eller indexuttryck utan argument x() härleder namnet x.

  • Ett XML-medlemsåtkomstuttryck x.<y>, x...<y>, x.@y härleder namnet y.

  • Ett XML-medlemsåtkomstuttryck som är målet för ett medlemsåtkomstuttryck x.<y>.z härleder namnet z.

  • Ett XML-medlemsåtkomstuttryck som är målet för ett anrop eller indexuttryck utan argument x.<y>.z() härleder namnet z.

  • Ett XML-medlemsåtkomstuttryck som är målet för ett anrop eller indexuttryck x.<y>(0) härleder namnet y.

Initiatorn tolkas som en tilldelning av uttrycket till det härledda namnet. Följande initiatorer är till exempel likvärdiga:

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

Om ett medlemsnamn härleds som står i konflikt med en befintlig medlem av typen, till exempel GetHashCode, uppstår ett kompileringstidsfel. Till skillnad från vanliga medlemsinitierare tillåter anonyma objektskapande uttryck inte att medlemsinitierare har cirkelreferenser eller refererar till en medlem innan den har initierats. Till exempel:

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

Om två anonyma klassskapandeuttryck inträffar inom samma metod och ger samma resulterande form – om egenskapsordningen, egenskapsnamnen och egenskapstyperna matchar – refererar båda till samma anonyma klass. Metodomfånget för en instans eller en delad medlemsvariabel med en initiering är konstruktorn där variabeln initieras.

Observera. Det är möjligt att en kompilator kan välja att förena anonyma typer ytterligare, till exempel på sammansättningsnivå, men det går inte att förlita sig på just nu.

Cast-uttryck

Ett cast-uttryck tvingar ett uttryck till en viss typ. Specifika gjutna nyckelord tvingar uttryck till de primitiva typerna. Tre allmänna nyckelord, CType, TryCast och DirectCast, tvingar ett uttryck till en typ.

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 och TryCast har särskilda beteenden. På grund av detta stöder de bara interna konverteringar. Dessutom kan måltypen i ett TryCast uttryck inte vara en värdetyp. Användardefinierade konverteringsoperatorer beaktas inte när DirectCast eller TryCast används. (Obs! Konverteringsuppsättningen och DirectCastTryCast stödet är begränsade eftersom de implementerar "interna CLR"-konverteringar. Syftet med DirectCast är att tillhandahålla funktionen i "unbox"-instruktionen, medan syftet med TryCast är att tillhandahålla funktionerna i "isinst"-instruktionen. Eftersom de mappas till CLR-instruktioner skulle stöd för konverteringar som inte stöds direkt av CLR besegra det avsedda syftet.)

DirectCast konverterar uttryck som skrivs som Object annorlunda än CType. När du konverterar ett uttryck av typen Object vars körningstyp är en primitiv värdetyp utlöser DirectCast ett System.InvalidCastException undantag om den angivna typen inte är samma som körningstypen för uttrycket eller om System.NullReferenceException uttrycket utvärderas till Nothing. (Obs! Som nämnts ovan DirectCast mappar direkt till CLR-instruktionen "unbox" när typen av uttryck är Object. Däremot CType omvandlas till ett anrop till en runtime-hjälp för att utföra konverteringen så att konverteringar mellan primitiva typer kan stödjas. Om ett Object uttryck konverteras till en primitiv värdetyp och typen av den faktiska instansen matchar måltypen blir DirectCast den betydligt snabbare än CType.)

TryCast konverterar uttryck men utlöser inget undantag om uttrycket inte kan konverteras till måltypen. TryCast I stället resulterar det i Nothing att uttrycket inte kan konverteras vid körning. (Obs! Som nämnts ovan TryCast mappar direkt till CLR-instruktionen "isinst". Genom att kombinera typkontrollen och konverteringen till en enda åtgärd TryCast kan det vara billigare än att göra en TypeOf ... Is och sedan en CType.)

Till exempel:

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

Om det inte finns någon konvertering från typen av uttryck till den angivna typen uppstår ett kompileringsfel. Annars klassificeras uttrycket som ett värde och resultatet är det värde som genereras av konverteringen.

Operatoruttryck

Det finns två typer av operatorer. Unary-operatorer tar en operand och använder prefix notation (till exempel -x). Binära operatorer tar två operander och använder infix-notation (till exempel x + y). Med undantag för relationsoperatorerna, vilket alltid resulterar i Boolean, resulterar en operator som definierats för en viss typ i den typen. Operanderna till en operator måste alltid klassificeras som ett värde. resultatet av ett operatoruttryck klassificeras som ett värde.

OperatorExpression
    : ArithmeticOperatorExpression
    | RelationalOperatorExpression
    | LikeOperatorExpression
    | ConcatenationOperatorExpression
    | ShortCircuitLogicalOperatorExpression
    | LogicalOperatorExpression
    | ShiftOperatorExpression
    | AwaitOperatorExpression
    ;

Operatorprioritet och associativitet

När ett uttryck innehåller flera binära operatorer styr operatorernas prioritet i vilken ordning de enskilda binära operatorerna utvärderas. Uttrycket x + y * z utvärderas till exempel som x + (y * z) eftersom operatorn * har högre prioritet än operatorn + . I följande tabell visas de binära operatorerna i fallande prioritetsordning:

Kategori Operatörer
Primär Alla uttryck som inte är operatorer
Invänta Await
Exponentiering ^
Unary negation +, -
Multiplikativ *, /
Heltalsdivision \
Modulus Mod
Tillsats +, -
Sammanfogning &
Skifta <<, >>
Relationell =, <>, <, >, <=, >=, , Like, , IsIsNot
Logiskt INTE Not
Logiskt OCH And, AndAlso
Logiskt ELLER Or, OrElse
Logisk XOR Xor

När ett uttryck innehåller två operatorer med samma prioritet styr operatorernas associativitet ordningen i vilken åtgärderna utförs. Alla binära operatorer är vänster-associativa, vilket innebär att åtgärder utförs från vänster till höger. Prioritet och associativitet kan styras med parentesiska uttryck.

Objektoperandar

Förutom de vanliga typer som stöds av varje operator stöder alla operatorer operander av typen Object. Operatorer som tillämpas på Object operander hanteras på samma sätt som metodanrop som görs på Object värden: ett sent metodanrop kan väljas, i vilket fall operandernas körningstyp, i stället för kompileringstidstypen, avgör åtgärdens giltighet och typ. Om strikt semantik anges av kompileringsmiljön eller av Option Strict, orsakar alla operatorer med operander av typen Object ett kompileringsfel, förutom operatorerna TypeOf...Is, Is och IsNot .

När operatorupplösningen avgör att en åtgärd ska utföras sent är resultatet av åtgärden resultatet av att operatorn tillämpas på operandtyperna om körningstyperna för operanderna är typer som stöds av operatorn. Värdet Nothing behandlas som standardvärdet för den andra operandtypen i ett binärt operatoruttryck. I ett unary-operatoruttryck, eller om båda operanderna är Nothing i ett binärt operatoruttryck, är Integer typen av åtgärden eller den enda resultattypen för operatorn, om operatorn inte resulterar i Integer. Resultatet av åtgärden skickas alltid tillbaka till Object. Om operandtyperna inte har någon giltig operator genereras ett System.InvalidCastException undantag. Konverteringar vid körning sker utan hänsyn till om de är implicita eller explicita.

Om resultatet av en numerisk binär åtgärd skulle generera ett undantag för spill (oavsett om heltalsöverflödeskontrollen är på eller av) höjs resultattypen upp till nästa bredare numeriska typ, om möjligt. Tänk till exempel på följande kod:

Module Test
    Sub Main()
        Dim o As Object = CObj(CByte(2)) * CObj(CByte(255))

        Console.WriteLine(o.GetType().ToString() & " = " & o)
    End Sub
End Module

Följande resultat skrivs ut:

System.Int16 = 512

Om det inte finns någon bredare numerisk typ för att lagra talet genereras ett System.OverflowException undantag.

Operatorupplösning

Med tanke på en operatortyp och en uppsättning operander avgör operatorupplösningen vilken operator som ska användas för operanderna. När du löser operatorer betraktas användardefinierade operatorer först med hjälp av följande steg:

  1. För det första samlas alla kandidatoperatörer in. Kandidatoperatorerna är alla användardefinierade operatorer av den specifika operatortypen i källtypen och alla användardefinierade operatorer av den specifika typen i måltypen. Om källtypen och måltypen är relaterade betraktas vanliga operatorer bara en gång.

  2. Sedan tillämpas överbelastningsupplösning på operatorer och operander för att välja den mest specifika operatorn. När det gäller binära operatorer kan detta resultera i ett sent bundet anrop.

När du samlar in kandidatoperatorerna för en typ T?används operatorerna av typen T i stället. TAlla användardefinierade operatorer som endast omfattar icke-nullbara värdetyper lyfts också. En lyftad operator använder den nullbara versionen av alla värdetyper, med undantag för IsTrue returtyperna och IsFalse (som måste vara Boolean). Lyfta operatorer utvärderas genom att konvertera operanderna till deras icke-nullbara version, sedan utvärdera den användardefinierade operatorn och sedan konvertera resultattypen till dess null-version. Om ether operand är Nothingär resultatet av uttrycket ett värde som Nothing skrivs som den nullbara versionen av resultattypen. Till exempel:

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

Om operatorn är en binär operator och en av operanderna är referenstyp, lyfts även operatorn, men alla bindningar till operatorn genererar ett fel. Till exempel:

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

Observera. Den här regeln finns eftersom vi har funderat på om vi vill lägga till referenstyper för null-spridning i en framtida version, i vilket fall beteendet för binära operatorer mellan de två typerna skulle ändras.

Precis som med konverteringar är användardefinierade operatorer alltid att föredra framför hissade operatorer.

När du löser överlagrade operatorer kan det finnas skillnader mellan klasser som definierats i Visual Basic och de som definierats på andra språk:

  • På andra språk Notkan , Andoch Or vara överbelastade både som logiska operatorer och bitvis operatorer. Vid import från en extern sammansättning godkänns endera formuläret som en giltig överlagring för dessa operatorer. För en typ som definierar både logiska operatorer och bitvis-operatorer kommer dock endast bitvis implementering att beaktas.

  • På andra språk >> och << kan vara överbelastad både som signerade operatorer och osignerade operatorer. Vid import från en extern sammansättning godkänns endera formuläret som en giltig överlagring. För en typ som definierar både signerade och osignerade operatorer beaktas dock endast den signerade implementeringen.

  • Om ingen användardefinierad operator är mest specifik för operanderna kommer inbyggda operatorer att övervägas. Om ingen inbyggd operator har definierats för operanderna och någon av operanderna har typen Object kommer operatorn att matchas sent bunden. annars resulterar ett kompileringsfel.

I tidigare versioner av Visual Basic, om det fanns exakt en operand av typen Object och inga tillämpliga användardefinierade operatorer, och inga tillämpliga inbyggda operatorer, så var det ett fel. Från och med Visual Basic 11 löses den nu sent bunden. Till exempel:

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

En typ T som har en inbyggd operator definierar också samma operator för T?. Resultatet av operatorn på T? blir detsamma som för T, förutom att om någon av operanderna är Nothing, blir Nothing resultatet av operatorn (dvs. null-värdet sprids). För att matcha typen av en åtgärd ? tas bort från alla operander som har dem, typen av åtgärden bestäms och en ? läggs till i typen av åtgärden om någon av operanderna var nullbara värdetyper. Till exempel:

Dim v1? As Integer = 10
Dim v2 As Long = 20

' Type of operation will be Long?
Console.WriteLine(v1 + v2)

Varje operator listar de inbyggda typer som definieras för och vilken typ av åtgärd som utförs med tanke på operandtyperna. Resultatet av typen av en inbyggd åtgärd följer dessa allmänna regler:

  • Om alla operander är av samma typ och operatorn definieras för typen sker ingen konvertering och operatorn för den typen används.

  • Alla operander vars typ inte har definierats för operatorn konverteras med hjälp av följande steg och operatorn matchas mot de nya typerna:

    • Operand konverteras till nästa bredaste typ som definieras för både operatorn och operanden och till vilken den implicit är konvertibel.

    • Om det inte finns någon sådan typ konverteras operanden till nästa smalaste typ som definieras för både operatorn och operanden och till vilken den implicit är konvertibel.

    • Om det inte finns någon sådan typ eller om konverteringen inte kan ske uppstår ett kompileringsfel.

  • I annat fall konverteras operanderna till de bredare operandtyperna och operatorn för den typen används. Om den smalare operandtypen inte implicit kan konverteras till den bredare operatortypen uppstår ett kompileringsfel.

Trots dessa allmänna regler finns det dock ett antal särskilda fall som anges i operatörsresultattabellerna.

Observera. Av formateringsskäl förkortar operatortyptabellerna de fördefinierade namnen till de två första tecknen. Så "By" är Byte, "UI" är UInteger, "St" är Stringosv. "Err" innebär att det inte finns någon åtgärd definierad för de angivna operandtyperna.

Aritmetiska operatorer

Operatorerna *, /, \, ^, Modoch +- är de aritmetiska operatorerna.

ArithmeticOperatorExpression
    : UnaryPlusExpression
    | UnaryMinusExpression
    | AdditionOperatorExpression
    | SubtractionOperatorExpression
    | MultiplicationOperatorExpression
    | DivisionOperatorExpression
    | ModuloOperatorExpression
    | ExponentOperatorExpression
    ;

Flyttalsaritmetiska åtgärder kan utföras med högre precision än åtgärdens resultattyp. Vissa maskinvaruarkitekturer stöder till exempel en "utökad" eller "lång dubbel" flyttal med större intervall och precision än Double typen, och utför implicit alla flyttalsåtgärder med den här typen med högre precision. Maskinvaruarkitekturer kan göras för att utföra flyttalsoperationer med mindre precision endast till orimliga prestandakostnader. I stället för att kräva en implementering för att förlora både prestanda och precision tillåter Visual Basic att typen med högre precision används för alla flyttalsåtgärder. Förutom att leverera mer exakta resultat har detta sällan några mätbara effekter. Men i uttryck i formuläret x * y / z, där multiplikationen ger ett resultat som ligger utanför Double intervallet, men den efterföljande divisionen tar det tillfälliga resultatet tillbaka till Double intervallet, kan det faktum att uttrycket utvärderas i ett format med högre intervall orsaka att ett ändligt resultat skapas i stället för oändlighet.

Unary Plus-operator

UnaryPlusExpression
    : '+' Expression
    ;

Unary plus-operatorn definieras för typerna Byte, SByte, UShort, Short, UInteger, Integer, LongULong, Single, Doubleoch Decimal .

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Sh SB Vid Sh USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob

Unary Minus-operator

UnaryMinusExpression
    : '-' Expression
    ;

Operatorn unary minus definieras för följande typer:

SByte, Short, Integeroch Long. Resultatet beräknas genom att operanden subtraheras från noll. Om heltalsöverflödeskontroll är aktiverat och värdet för operanden är det maximala negativa SByte, Short, Integereller Long, genereras ett System.OverflowException undantag. Annars, om värdet för operand är det maximala negativa SByte, Short, Integereller Long, resultatet är samma värde, och spillet inte rapporteras.

Single och Double. Resultatet är operandens värde med dess tecken inverterat, inklusive värdena 0 och Infinity. Om operand är NaN blir resultatet också NaN.

Decimal. Resultatet beräknas genom att operanden subtraheras från noll.

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Sh SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob

Additionsoperator

Additionsoperatorn beräknar summan av de två operanderna.

AdditionOperatorExpression
    : Expression '+' LineTerminator? Expression
    ;

Additionsoperatorn definieras för följande typer:

  • Byte, SByte, UShort, Short, UInteger, Integer, ULongoch Long. Om heltalsöverflödeskontrollen är på och summan ligger utanför resultattypens intervall genereras ett System.OverflowException undantag. I annat fall rapporteras inte spill och några betydande högordningsbitar av resultatet ignoreras.

  • Single och Double. Summan beräknas enligt reglerna i IEEE 754-aritmetik.

  • Decimal. Om det resulterande värdet är för stort för att representeras i decimalformat genereras ett System.OverflowException undantag. Om resultatvärdet är för litet för att representeras i decimalformatet är resultatet 0.

  • String. De två String operanderna sammanfogas tillsammans.

  • Date. Typen System.DateTime definierar överlagrade tilläggsoperatorer. Eftersom System.DateTime motsvarar den inbyggda Date typen är dessa operatorer också tillgängliga för Date typen.

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Sh SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
SB SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
Av Vid Sh USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
USA USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
I I Lo Lo De De Si Gör Fela Fela Gör Ob
Användargränssnitt Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
Lo Lo De De Si Gör Fela Fela Gör Ob
UL UL De Si Gör Fela Fela Gör Ob
De De Si Gör Fela Fela Gör Ob
Si Si Gör Fela Fela Gör Ob
Göra Gör Fela Fela Gör Ob
Da Sankt Fela Sankt Ob
Ch Sankt Sankt Ob
Sankt Sankt Ob
Ob Ob

Subtraktionsoperator

Subtraktionsoperatorn subtraherar den andra operanden från den första operanden.

SubtractionOperatorExpression
    : Expression '-' LineTerminator? Expression
    ;

Subtraktionsoperatorn definieras för följande typer:

  • Byte, SByte, UShort, Short, UInteger, Integer, ULongoch Long. Om kontroll av heltalsspill är aktiverat och skillnaden ligger utanför resultattypens intervall genereras ett System.OverflowException undantag. I annat fall rapporteras inte spill och några betydande högordningsbitar av resultatet ignoreras.

  • Single och Double. Skillnaden beräknas enligt reglerna i IEEE 754-aritmetik.

  • Decimal. Om det resulterande värdet är för stort för att representeras i decimalformat genereras ett System.OverflowException undantag. Om resultatvärdet är för litet för att representeras i decimalformatet är resultatet 0.

  • Date. Typen System.DateTime definierar överlagrade subtraktionsoperatorer. Eftersom System.DateTime motsvarar den inbyggda Date typen är dessa operatorer också tillgängliga för Date typen.

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Sh SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
SB SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
Av Vid Sh USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
USA USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
I I Lo Lo De De Si Gör Fela Fela Gör Ob
Användargränssnitt Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
Lo Lo De De Si Gör Fela Fela Gör Ob
UL UL De Si Gör Fela Fela Gör Ob
De De Si Gör Fela Fela Gör Ob
Si Si Gör Fela Fela Gör Ob
Göra Gör Fela Fela Gör Ob
Da Fela Fela Fela Fela
Ch Fela Fela Fela
Sankt Gör Ob
Ob Ob

Multiplikationsoperator

Multiplikationsoperatorn beräknar produkten av två operander.

MultiplicationOperatorExpression
    : Expression '*' LineTerminator? Expression
    ;

Multiplikationsoperatorn definieras för följande typer:

  • Byte, SByte, UShort, Short, UInteger, Integer, ULongoch Long. Om kontroll av heltalsspill är aktiverat och produkten ligger utanför resultattypens intervall genereras ett System.OverflowException undantag. I annat fall rapporteras inte spill och några betydande högordningsbitar av resultatet ignoreras.

  • Single och Double. Produkten beräknas enligt reglerna i IEEE 754-aritmetik.

  • Decimal. Om det resulterande värdet är för stort för att representeras i decimalformat genereras ett System.OverflowException undantag. Om resultatvärdet är för litet för att representeras i decimalformatet är resultatet 0.

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Sh SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
SB SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
Av Vid Sh USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
USA USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
I I Lo Lo De De Si Gör Fela Fela Gör Ob
Användargränssnitt Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
Lo Lo De De Si Gör Fela Fela Gör Ob
UL UL De Si Gör Fela Fela Gör Ob
De De Si Gör Fela Fela Gör Ob
Si Si Gör Fela Fela Gör Ob
Göra Gör Fela Fela Gör Ob
Da Fela Fela Fela Fela
Ch Fela Fela Fela
Sankt Gör Ob
Ob Ob

Divisionsoperatorer

Divisionsoperatorer beräknar kvoten för två operander. Det finns två divisionsoperatorer: den vanliga divisionsoperatorn (flyttal) och heltalsdivisionsoperatorn.

DivisionOperatorExpression
    : FPDivisionOperatorExpression
    | IntegerDivisionOperatorExpression
    ;

FPDivisionOperatorExpression
    : Expression '/' LineTerminator? Expression
    ;

IntegerDivisionOperatorExpression
    : Expression '\\' LineTerminator? Expression
    ;

Den vanliga divisionsoperatorn definieras för följande typer:

  • Single och Double. Kvoten beräknas enligt reglerna i IEEE 754-aritmetik.

  • Decimal. Om värdet för rätt operand är noll genereras ett System.DivideByZeroException undantag. Om det resulterande värdet är för stort för att representeras i decimalformat genereras ett System.OverflowException undantag. Om resultatvärdet är för litet för att representera i decimalformatet blir resultatet noll. Resultatets skala, före avrundning, är den närmaste skalan till önskad skala som bevarar ett resultat som är lika med det exakta resultatet. Den önskade skalan är skalan för den första operanden mindre skalan för den andra operanden.

Enligt regler för normal operatormatchning skulle regelbunden uppdelning enbart mellan operander av typer som Byte, Short, Integeroch Long leda till att båda operanderna konverteras till typen Decimal. Men när du utför operatormatchning på divisionsoperatorn när ingen av typerna är Decimal, Double anses den vara smalare än Decimal. Den här konventionen följs eftersom Double division är effektivare än Decimal division.

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Gör Gör Gör Gör Gör Gör Gör Gör Gör De Si Gör Fela Fela Gör Ob
SB Gör Gör Gör Gör Gör Gör Gör Gör De Si Gör Fela Fela Gör Ob
Av Gör Gör Gör Gör Gör Gör Gör De Si Gör Fela Fela Gör Ob
Sh Gör Gör Gör Gör Gör Gör De Si Gör Fela Fela Gör Ob
USA Gör Gör Gör Gör Gör De Si Gör Fela Fela Gör Ob
I Gör Gör Gör Gör De Si Gör Fela Fela Gör Ob
Användargränssnitt Gör Gör Gör De Si Gör Fela Fela Gör Ob
Lo Gör Gör De Si Gör Fela Fela Gör Ob
UL Gör De Si Gör Fela Fela Gör Ob
De De Si Gör Fela Fela Gör Ob
Si Si Gör Fela Fela Gör Ob
Göra Gör Fela Fela Gör Ob
Da Fela Fela Fela Fela
Ch Fela Fela Fela
Sankt Gör Ob
Ob Ob

Heltalsdivisionsoperatorn definieras för Byte, SByte, UShort, Short, UInteger, Integer, ULongoch Long. Om värdet för rätt operand är noll genereras ett System.DivideByZeroException undantag. Divisionen avrundar resultatet mot noll, och det absoluta värdet för resultatet är det största möjliga heltalet som är mindre än det absoluta värdet för kvoten för de två operanderna. Resultatet är noll eller positivt när de två operanderna har samma tecken och noll eller negativa när de två operanderna har motsatta tecken. Om den vänstra operanden är den maximala negativa , , eller Long, och den högra operanden är -1, uppstår ett spill. Om heltalsöverflödet kontrolleras utlöses ett System.OverflowExceptionIntegerundantag. ShortSByte Annars rapporteras inte spillet och resultatet är i stället värdet för den vänstra operanden.

Observera. Eftersom de två operanderna för osignerade typer alltid är noll eller positiva är resultatet alltid noll eller positivt. Eftersom resultatet av uttrycket alltid blir mindre än eller lika med det största av de två operanderna är det inte möjligt att ett spill uppstår. Eftersom sådan heltalsöverflödeskontroll inte utförs för heltalsdelning med två osignerade heltal. Resultatet är typen som den vänstra operanden.

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Sh SB Sh Sh I I Lo Lo Lo Lo Lo Lo Fela Fela Lo Ob
SB SB Sh Sh I I Lo Lo Lo Lo Lo Lo Fela Fela Lo Ob
Av Vid Sh USA I Användargränssnitt (UI) Lo UL Lo Lo Lo Fela Fela Lo Ob
Sh Sh I I Lo Lo Lo Lo Lo Lo Fela Fela Lo Ob
USA USA I Användargränssnitt (UI) Lo UL Lo Lo Lo Fela Fela Lo Ob
I I Lo Lo Lo Lo Lo Lo Fela Fela Lo Ob
Användargränssnitt Användargränssnitt (UI) Lo UL Lo Lo Lo Fela Fela Lo Ob
Lo Lo Lo Lo Lo Lo Fela Fela Lo Ob
UL UL Lo Lo Lo Fela Fela Lo Ob
De Lo Lo Lo Fela Fela Lo Ob
Si Lo Lo Fela Fela Lo Ob
Göra Lo Fela Fela Lo Ob
Da Fela Fela Fela Fela
Ch Fela Fela Fela
Sankt Lo Ob
Ob Ob

Mod-operator

Operatorn Mod (modulo) beräknar resten av divisionen mellan två operander.

ModuloOperatorExpression
    : Expression 'Mod' LineTerminator? Expression
    ;

Operatorn Mod definieras för följande typer:

  • Byte, SByte, UShort, Short, UInteger, Integeroch ULongLong. Resultatet av x Mod y är värdet som genereras av x - (x \ y) * y. Om y är noll genereras ett System.DivideByZeroException undantag. Modulooperatorn orsakar aldrig ett spill.

  • Single och Double. Resten beräknas enligt reglerna i IEEE 754-aritmetik.

  • Decimal. Om värdet för rätt operand är noll genereras ett System.DivideByZeroException undantag. Om det resulterande värdet är för stort för att representeras i decimalformat genereras ett System.OverflowException undantag. Om resultatvärdet är för litet för att representera i decimalformatet blir resultatet noll.

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Sh SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
SB SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
Av Vid Sh USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
USA USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
I I Lo Lo De De Si Gör Fela Fela Gör Ob
Användargränssnitt Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
Lo Lo De De Si Gör Fela Fela Gör Ob
UL UL De Si Gör Fela Fela Gör Ob
De De Si Gör Fela Fela Gör Ob
Si Si Gör Fela Fela Gör Ob
Göra Gör Fela Fela Gör Ob
Da Fela Fela Fela Fela
Ch Fela Fela Fela
Sankt Gör Ob
Ob Ob

Exponentiationsoperator

Exponentiationsoperatorn beräknar den första operand som upphöjts till den andra operandens kraft.

ExponentOperatorExpression
    : Expression '^' LineTerminator? Expression
    ;

Exponentiationsoperatorn definieras för typen Double. Värdet beräknas enligt reglerna i IEEE 754-aritmetik.

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Gör Gör Gör Gör Gör Gör Gör Gör Gör Gör Gör Gör Fela Fela Gör Ob
SB Gör Gör Gör Gör Gör Gör Gör Gör Gör Gör Gör Fela Fela Gör Ob
Av Gör Gör Gör Gör Gör Gör Gör Gör Gör Gör Fela Fela Gör Ob
Sh Gör Gör Gör Gör Gör Gör Gör Gör Gör Fela Fela Gör Ob
USA Gör Gör Gör Gör Gör Gör Gör Gör Fela Fela Gör Ob
I Gör Gör Gör Gör Gör Gör Gör Fela Fela Gör Ob
Användargränssnitt Gör Gör Gör Gör Gör Gör Fela Fela Gör Ob
Lo Gör Gör Gör Gör Gör Fela Fela Gör Ob
UL Gör Gör Gör Gör Fela Fela Gör Ob
De Gör Gör Gör Fela Fela Gör Ob
Si Gör Gör Fela Fela Gör Ob
Göra Gör Fela Fela Gör Ob
Da Fela Fela Fela Fela
Ch Fela Fela Fela
Sankt Gör Ob
Ob Ob

Relationsoperatorer

Relationsoperatorerna jämför värden med varandra. Jämförelseoperatorerna är =, <>, <, >, <=och >=.

RelationalOperatorExpression
    : Expression '=' LineTerminator? Expression
    | Expression '<' '>' LineTerminator? Expression
    | Expression '<' LineTerminator? Expression
    | Expression '>' LineTerminator? Expression
    | Expression '<' '=' LineTerminator? Expression
    | Expression '>' '=' LineTerminator? Expression
    ;

Alla relationsoperatorer resulterar i ett Boolean värde.

Relationsoperatorerna har följande allmänna betydelse:

  • Operatorn = testar om de två operanderna är lika med.

  • Operatorn <> testar om de två operanderna inte är lika med.

  • Operatorn < testar om den första operanden är mindre än den andra operanden.

  • Operatorn > testar om den första operanden är större än den andra operanden.

  • Operatorn <= testar om den första operanden är mindre än eller lika med den andra operanden.

  • Operatorn >= testar om den första operanden är större än eller lika med den andra operanden.

Relationsoperatorerna definieras för följande typer:

  • Boolean. Operatorerna jämför sanningsvärdena för de två operanderna. True anses vara mindre än False, vilket matchar deras numeriska värden.

  • Byte, SByte, UShort, Short, UInteger, Integer, ULongoch Long. Operatorerna jämför de numeriska värdena för de två integrerade operanderna.

  • Single och Double. Operatörerna jämför operanderna enligt reglerna i IEEE 754-standarden.

  • Decimal. Operatorerna jämför de numeriska värdena för de två decimaloperatorerna.

  • Date. Operatorerna returnerar resultatet av att jämföra de två datum-/tidsvärdena.

  • Char. Operatorerna returnerar resultatet av att jämföra de två Unicode-värdena.

  • String. Operatorerna returnerar resultatet av att jämföra de två värdena med antingen en binär jämförelse eller en textjämförelse. Jämförelsen som används bestäms av kompileringsmiljön och -instruktionen Option Compare . En binär jämförelse avgör om det numeriska Unicode-värdet för varje tecken i varje sträng är detsamma. En textjämförelse gör en Unicode-textjämförelse baserat på den aktuella kultur som används i .NET Framework. När du gör en strängjämförelse motsvarar ett null-värde strängliteralen "".

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Bo SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Bo Ob
SB SB Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
Av Vid Sh USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
Sh Sh I I Lo Lo De De Si Gör Fela Fela Gör Ob
USA USA I Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
I I Lo Lo De De Si Gör Fela Fela Gör Ob
Användargränssnitt Användargränssnitt (UI) Lo UL De Si Gör Fela Fela Gör Ob
Lo Lo De De Si Gör Fela Fela Gör Ob
UL UL De Si Gör Fela Fela Gör Ob
De De Si Gör Fela Fela Gör Ob
Si Si Gör Fela Fela Gör Ob
Göra Gör Fela Fela Gör Ob
Da Da Fela Da Ob
Ch Ch Sankt Ob
Sankt Sankt Ob
Ob Ob

Gilla-operator

Operatorn Like avgör om en sträng matchar ett visst mönster.

LikeOperatorExpression
    : Expression 'Like' LineTerminator? Expression
    ;

Operatorn Like definieras för String typen. Den första operand är strängen som matchas, och den andra operand är mönstret att matcha mot. Mönstret består av Unicode-tecken. Följande teckensekvenser har särskilda betydelser:

  • Tecknet ? matchar ett enskilt tecken.

  • Tecknet * matchar noll eller fler tecken.

  • Tecknet # matchar valfri ensiffrig (0–9).

  • En lista med tecken omgivna av hakparenteser ([ab...]) matchar alla enskilda tecken i listan.

  • En lista över tecken som omges av hakparenteser och prefixet av ett utropstecken ([!ab...]) matchar ett enskilt tecken som inte finns i teckenlistan.

  • Två tecken i en teckenlista avgränsade med ett bindestreck (-) anger ett intervall med Unicode-tecken som börjar med det första tecknet och slutar med det andra tecknet. Om det andra tecknet inte är senare i sorteringsordningen än det första tecknet inträffar ett körningsundanstag. Ett bindestreck som visas i början eller slutet av en teckenlista anger sig själv.

För att matcha specialtecken vänster hakparentes ([), frågetecken (?), taltecken (#) och asterisk (*), måste hakparenteser omsluta dem. Den högra hakparentesen (]) kan inte användas i en grupp för att matcha sig själv, men den kan användas utanför en grupp som ett enskilt tecken. Teckensekvensen [] anses vara strängliteralen "".

Observera att teckenjämförelser och sortering för teckenlistor är beroende av vilken typ av jämförelser som används. Om binära jämförelser används baseras teckenjämförelser och ordning på de numeriska Unicode-värdena. Om textjämförelser används baseras teckenjämförelser och ordning på det aktuella nationella språket som används i .NET Framework.

På vissa språk representerar specialtecken i alfabetet två separata tecken och vice versa. Till exempel använder flera språk tecknet æ för att representera tecknen a och e när de visas tillsammans, medan tecknen ^ och O kan användas för att representera tecknet Ô. När du använder textjämförelser identifierar operatorn Like sådana kulturella ekvivalenser. I så fall matchar en förekomst av det enskilda specialtecknet i antingen mönster eller sträng motsvarande sekvens med två tecken i den andra strängen. På samma sätt matchar ett enskilt specialtecken i mönstret inom hakparenteser (i sig, i en lista eller i ett intervall) motsvarande sekvens med två tecken i strängen och vice versa.

I ett Like uttryck där båda operanderna är Nothing eller en operand har en inbyggd konvertering till String och den andra operanden är Nothing, Nothing behandlas som om det vore den tomma strängliteralen "".

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
SB Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
Av Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
Sh Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
USA Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
I Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
Användargränssnitt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
Lo Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
UL Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
De Sankt Sankt Sankt Sankt Sankt Sankt Ob
Si Sankt Sankt Sankt Sankt Sankt Ob
Göra Sankt Sankt Sankt Sankt Ob
Da Sankt Sankt Sankt Ob
Ch Sankt Sankt Ob
Sankt Sankt Ob
Ob Ob

Sammanfogningsoperator

ConcatenationOperatorExpression
    : Expression '&' LineTerminator? Expression
    ;

Sammanfogningsoperatorn definieras för alla inbyggda typer, inklusive de nullbara versionerna av de inbyggda värdetyperna. Den definieras också för sammanfogning mellan de typer som nämns ovan och System.DBNull, som behandlas som en Nothing sträng. Sammanfogningsoperatorn konverterar alla sina operander till String; i uttrycket anses alla konverteringar till String vara bredare, oavsett om strikta semantik används. Ett System.DBNull värde konverteras till den literal Nothing som skrivs som String. En nullbar värdetyp vars värde Nothing också konverteras till den literal Nothing som skrivs som String, i stället för att utlösa ett körningsfel.

En sammanlänkningsåtgärd resulterar i en sträng som är sammanlänkningen av de två operanderna i ordning från vänster till höger. Värdet Nothing behandlas som om det vore den tomma strängliteralen "".

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
SB Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
Av Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
Sh Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
USA Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
I Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
Användargränssnitt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
Lo Sankt Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
UL Sankt Sankt Sankt Sankt Sankt Sankt Sankt Ob
De Sankt Sankt Sankt Sankt Sankt Sankt Ob
Si Sankt Sankt Sankt Sankt Sankt Ob
Göra Sankt Sankt Sankt Sankt Ob
Da Sankt Sankt Sankt Ob
Ch Sankt Sankt Ob
Sankt Sankt Ob
Ob Ob

Logiska operatorer

Operatorerna And, Not, Oroch Xor kallas logiska operatorer.

LogicalOperatorExpression
    : 'Not' Expression
    | Expression 'And' LineTerminator? Expression
    | Expression 'Or' LineTerminator? Expression
    | Expression 'Xor' LineTerminator? Expression
    ;

De logiska operatorerna utvärderas på följande sätt:

  • För typen Boolean :

    • En logisk And åtgärd utförs på dess två operander.

    • En logisk Not åtgärd utförs på dess operand.

    • En logisk Or åtgärd utförs på dess två operander.

    • En logisk exklusivOr åtgärd utförs på dess två operander.

  • För Byte, SByte, UShort, Short, UInteger, Integer, ULong, Longoch alla uppräknade typer utförs den angivna åtgärden på varje bit av den binära representationen av de två operanderna:

    • And: Resultatbiten är 1 om båda bitarna är 1; annars är resultatbiten 0.

    • Not: Resultatbiten är 1 om biten är 0; annars är resultatbiten 1.

    • Or: Resultatbiten är 1 om endera biten är 1; annars är resultatbiten 0.

    • Xor: Resultatbiten är 1 om endera biten är 1 men inte båda bitarna. annars är resultatbiten 0 (dvs. 1 Xor 0 = 1, 1 Xor 1 = 0).

  • När de logiska operatorerna And och Or lyfts för typen Boolean?utökas de till att omfatta boolesk logik med tre värden som sådan:

    • And utvärderas till sant om båda operanderna är sanna; false om någon av operanderna är falsk; Nothing annars.

    • Or utvärderas till sant om någon av operanderna är sanna; false är att båda operanderna är falska; Nothing annars.

Till exempel:

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

Observera. Helst skulle de logiska operatorerna And och Or lyftas med hjälp av trevärdeslogik för alla typer som kan användas i ett booleskt uttryck (dvs. en typ som implementerar IsTrue och IsFalse), på samma sätt som AndAlso och OrElse kortslutning över alla typer som kan användas i ett booleskt uttryck. Tyvärr tillämpas trevärdeslyft endast på Boolean?, så användardefinierade typer som önskar trevärdeslogik måste göra det manuellt genom att And definiera och Or operatorer för deras nullbara version.

Inga överflöden är möjliga från dessa operationer. Operatorerna för uppräknad typ utför bitvis-åtgärden på den underliggande typen av den uppräknade typen, men returvärdet är den uppräknade typen.

Inte åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo SB Vid Sh USA I Användargränssnitt (UI) Lo UL Lo Lo Lo Fela Fela Lo Ob

Och, eller, Xor-åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Bo SB Sh Sh I I Lo Lo Lo Lo Lo Lo Fela Fela Bo Ob
SB SB Sh Sh I I Lo Lo Lo Lo Lo Lo Fela Fela Lo Ob
Av Vid Sh USA I Användargränssnitt (UI) Lo UL Lo Lo Lo Fela Fela Lo Ob
Sh Sh I I Lo Lo Lo Lo Lo Lo Fela Fela Lo Ob
USA USA I Användargränssnitt (UI) Lo UL Lo Lo Lo Fela Fela Lo Ob
I I Lo Lo Lo Lo Lo Lo Fela Fela Lo Ob
Användargränssnitt Användargränssnitt (UI) Lo UL Lo Lo Lo Fela Fela Lo Ob
Lo Lo Lo Lo Lo Lo Fela Fela Lo Ob
UL UL Lo Lo Lo Fela Fela Lo Ob
De Lo Lo Lo Fela Fela Lo Ob
Si Lo Lo Fela Fela Lo Ob
Göra Lo Fela Fela Lo Ob
Da Fela Fela Fela Fela
Ch Fela Fela Fela
Sankt Lo Ob
Ob Ob

Kortslutna logiska operatorer

Operatorerna AndAlso och OrElse är kortslutningsversionerna av de And logiska operatorerna och Or .

ShortCircuitLogicalOperatorExpression
    : Expression 'AndAlso' LineTerminator? Expression
    | Expression 'OrElse' LineTerminator? Expression
    ;

På grund av deras kortslutningsbeteende utvärderas inte den andra operanden vid körning om operatorresultatet är känt efter att ha utvärderat den första operanden.

De logiska kortslutningsoperatorerna utvärderas på följande sätt:

  • Om den första operanden i en AndAlso åtgärd utvärderas till False eller returnerar Sant från operatorn IsFalse returnerar uttrycket sin första operande. Annars utvärderas den andra operanden och en logisk And åtgärd utförs på de två resultaten.

  • Om den första operanden i en OrElse åtgärd utvärderas till True eller returnerar Sant från operatorn IsTrue returnerar uttrycket sin första operande. Annars utvärderas den andra operanden och en logisk Or åtgärd utförs på dess två resultat.

Operatorerna AndAlso och OrElse definieras för typen Boolean, eller för någon typ T som överbelastar följande operatorer:

Public Shared Operator IsTrue(op As T) As Boolean
Public Shared Operator IsFalse(op As T) As Boolean

samt överlagring av motsvarande And operator eller 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

När du utvärderar operatorerna AndAlso eller OrElse utvärderas den första operanden bara en gång och den andra operanden utvärderas eller utvärderas antingen inte exakt en gång. Tänk till exempel på följande kod:

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

Följande resultat skrivs ut:

And: False True
Or: True False
AndAlso: False
OrElse: True

Om den första operanden var null Boolean?i den upplyfta formen av AndAlso operatorerna och OrElse utvärderas den andra operanden, men resultatet är alltid null Boolean?.

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Bo Bo Bo Bo Bo Bo Bo Bo Bo Bo Bo Bo Bo Fela Fela Bo Ob
SB Bo Bo Bo Bo Bo Bo Bo Bo Bo Bo Bo Fela Fela Bo Ob
Av Bo Bo Bo Bo Bo Bo Bo Bo Bo Bo Fela Fela Bo Ob
Sh Bo Bo Bo Bo Bo Bo Bo Bo Bo Fela Fela Bo Ob
USA Bo Bo Bo Bo Bo Bo Bo Bo Fela Fela Bo Ob
I Bo Bo Bo Bo Bo Bo Bo Fela Fela Bo Ob
Användargränssnitt Bo Bo Bo Bo Bo Bo Fela Fela Bo Ob
Lo Bo Bo Bo Bo Bo Fela Fela Bo Ob
UL Bo Bo Bo Bo Fela Fela Bo Ob
De Bo Bo Bo Fela Fela Bo Ob
Si Bo Bo Fela Fela Bo Ob
Göra Bo Fela Fela Bo Ob
Da Fela Fela Fela Fela
Ch Fela Fela Fela
Sankt Bo Ob
Ob Ob

Skiftoperatorer

De binära operatorerna << och >> utför bitväxlingsåtgärder.

ShiftOperatorExpression
    : Expression '<' '<' LineTerminator? Expression
    | Expression '>' '>' LineTerminator? Expression
    ;

Operatorerna definieras för typerna Byte, SByte, UShort, Short, UInteger, IntegerULong och Long . Till skillnad från de andra binära operatorerna bestäms resultattypen för en skiftåtgärd som om operatorn var en unary-operator med bara den vänstra operanden. Typen av rätt operand måste implicit konverteras till Integer och används inte för att fastställa åtgärdens resultattyp.

Operatorn << gör att bitarna i den första operanden flyttas till vänster om antalet platser som anges av skiftmängden. Högordningsbitarna utanför resultattypens intervall ignoreras och de tomma bitpositionerna i låg ordning är nollfyllda.

Operatorn >> gör att bitarna i den första operanden flyttas rätt på det antal platser som anges av skiftmängden. Lågordningsbitarna ignoreras och de tomma bitpositionerna i hög ordning är inställda på noll om den vänstra operanden är positiv eller till en om den är negativ. Om den vänstra operanden är av typen Byte, UShort, UIntegereller ULong de lediga högordningsbitarna är nollfyllda.

Skiftoperatorerna flyttar bitarna i den underliggande representationen av den första operanden med mängden av den andra operanden. Om värdet för den andra operanden är större än antalet bitar i den första operanden, eller om den är negativ, beräknas skiftbeloppet som RightOperand And SizeMask var SizeMask är:

LeftOperand-typ SizeMask
Byte, SByte 7 (&H7)
UShort, Short 15 (&HF)
UInteger, Integer 31 (&H1F)
ULong, Long 63 (&H3F)

Om skiftbeloppet är noll är resultatet av åtgärden identiskt med värdet för den första operanden. Inga överflöden är möjliga från dessa operationer.

Åtgärdstyp:

Bo SB Av Sh USA I Användargränssnitt Lo UL De Si Göra Da Ch Sankt Ob
Sh SB Vid Sh USA I Användargränssnitt (UI) Lo UL Lo Lo Lo Fela Fela Lo Ob

Booleska uttryck

Ett booleskt uttryck är ett uttryck som kan testas för att se om det är sant eller om det är falskt.

BooleanExpression
    : Expression
    ;

En typ T kan användas i ett booleskt uttryck om, i prioritetsordning:

  • T är Boolean eller Boolean?

  • T har en bredare konvertering till Boolean

  • T har en bredare konvertering till Boolean?

  • T definierar två pseudooperatorer IsTrue och IsFalse.

  • T har en begränsad konvertering till Boolean? som inte omfattar en konvertering från Boolean till Boolean?.

  • T har en begränsad konvertering till Boolean.

Observera. Det är intressant att notera att om Option Strict är av, kommer ett uttryck som har en begränsad konvertering till Boolean att accepteras utan ett kompileringsfel, men språket föredrar fortfarande en IsTrue operator om det finns. Detta beror på att Option Strict endast ändrar vad som är och inte accepteras av språket och aldrig ändrar den faktiska innebörden av ett uttryck. IsTrue Därför måste alltid föredras framför en begränsad konvertering, oavsett Option Strict.

Följande klass definierar till exempel inte en bredare konvertering till Boolean. Därför orsakar dess användning i -instruktionen If ett anrop till operatorn IsTrue .

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

Om ett booleskt uttryck skrivs som eller konverteras till Boolean eller Boolean?, är det sant om värdet är True och annars falskt.

Annars anropar ett booleskt uttryck operatorn IsTrue och returnerar True om operatorn returnerade True. Annars är det falskt (men anropar aldrig operatorn IsFalse ).

I följande exempel Integer har en begränsad konvertering till Boolean, så en null Integer? har en begränsad konvertering till både Boolean? (ger en null Boolean) och till Boolean (vilket genererar ett undantag). Den begränsade konverteringen till Boolean? föredras, och därför är värdet för "i" som ett booleskt uttryck därför False.

Dim i As Integer? = Nothing
If i Then Console.WriteLine()

Lambda-uttryck

Ett lambda-uttryck definierar en anonym metod som kallas lambda-metod. Lambda-metoder gör det enkelt att skicka "in-line"-metoder till andra metoder som tar ombudstyper.

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

Exemplet:

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

skrivs ut:

2 4 6 8

Ett lambda-uttryck börjar med valfria modifierare Async eller Iterator, följt av nyckelordet Function eller Sub och en parameterlista. Parametrar i ett lambda-uttryck kan inte deklareras Optional eller ParamArray ha attribut. Till skillnad från vanliga metoder härleds Objectinte automatiskt om du utelämnar en parametertyp för en lambda-metod. När en lambda-metod omklassificeras härleds i stället de utelämnade parametertyperna och ByRef modifierarna från måltypen. I föregående exempel kunde lambda-uttrycket ha skrivits som Function(x) x * 2, och det skulle ha härlett typen av x till Integer när lambda-metoden användes för att skapa en instans av ombudstypen IntFunc . Till skillnad från lokal variabelinferens uppstår ett kompileringsfel om en lambda-metodparameter utelämnar en typ men har en matris eller en nullbar namnmodifierare.

Ett vanligt lambda-uttryck är ett med varken Async eller Iterator modifierare.

Ett lambda-uttryck för iterator är ett med Iterator modifieraren och ingen Async modifierare. Det måste vara en funktion. När det omklassificeras till ett värde kan det bara omklassificeras till ett värde av delegattyp vars returtyp är IEnumerator, eller IEnumerable, eller IEnumerator(Of T) för IEnumerable(Of T) vissa T, och som inte har några ByRef-parametrar.

Ett asynkront lambda-uttryck är ett med Async modifieraren och ingen Iterator modifierare. En asynkron under lambda kan bara omklassificeras till ett värde av underdelsdelad typ utan ByRef-parametrar. En asynkron funktion lambda kan bara omklassificeras till ett värde av funktionsdelegattyp vars returtyp är Task eller Task(Of T) för vissa T, och som inte har några ByRef-parametrar.

Lambda-uttryck kan antingen vara enrads- eller flerradsuttryck. Lambda-uttryck med en rad Function innehåller ett enda uttryck som representerar värdet som returneras från lambda-metoden. Lambda-uttryck med en rad Sub innehåller en enda instruktion utan dess avslutande StatementTerminator. Till exempel:

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

Enrads lambda-konstruktioner binder mindre tätt än alla andra uttryck och uttryck. Function() x + 5"" motsvarar alltså "Function() (x+5)" snarare än "(Function() x) + 5". För att undvika tvetydighet får ett lambda-uttryck med en rad Sub inte innehålla en Dim-instruktion eller en etikettdeklarationsinstruktur. Om det inte omges av parenteser kan ett lambda-uttryck med en rad Sub inte omedelbart följas av ett kolon ":", en medlemsåtkomstoperator ".", en ordlistemedlemsåtkomstoperator "!" eller en öppen parentes "(". Den får inte innehålla någon block-instruktion (With, SyncLock, If...EndIf, While, For, Do, Using) eller ResumeOnError .

Observera. I lambda-uttrycket Function(i) x=itolkas brödtexten som ett uttryck (som testar om x och i är lika med). Men i lambda-uttrycket Sub(i) x=itolkas brödtexten som en instruktion (som tilldelar i ).x

Ett lambda-uttryck med flera rader innehåller ett instruktionsblock och måste avslutas med en lämplig End instruktion (dvs. End Function eller End Sub). Precis som med vanliga metoder måste en lambda-metod Function eller Sub -instruktion med flera rader vara End på sina egna rader. Till exempel:

' 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-uttryck Function med flera rader kan deklarera en returtyp men kan inte placera attribut på den. Om ett lambda-uttryck med flera rader inte deklarerar en returtyp, men returtypen kan härledas från kontexten där lambda-uttrycket Function används, används den returtypen. Annars beräknas funktionens returtyp på följande sätt:

  • I ett vanligt lambda-uttryck är returtypen den dominerande typen av uttryck i alla Return uttryck i instruktionsblocket.

  • I ett asynkront lambda-uttryck är Task(Of T) returtypen där T är den dominerande typen av uttryck i alla Return uttryck i instruktionsblocket.

  • I ett lambda-uttryck för iterator är IEnumerable(Of T) returtypen den T dominerande typen av uttryck i alla Yield uttryck i instruktionsblocket.

Till exempel:

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

Om det i samtliga fall inte finns några Return (respektive Yield) instruktioner, eller om det inte finns någon dominerande typ bland dem, och strikta semantik används, uppstår ett kompileringsfel. Annars är den dominerande typen implicit Object.

Observera att returtypen beräknas från alla Return instruktioner, även om de inte kan nås. Till exempel:

' Return type is Double
Dim x = Function()
              Return 10
               Return 10.50
          End Function

Det finns ingen implicit returvariabel eftersom det inte finns något namn på variabeln.

Instruktionsblocken i lambda-uttryck med flera rader har följande begränsningar:

  • On Error och Resume -instruktioner tillåts inte, även om Try instruktioner tillåts.

  • Statiska lokala objekt kan inte deklareras i lambda-uttryck med flera rader.

  • Det går inte att förgrena sig till eller ut ur instruktionsblocket i ett lambda-uttryck med flera rader, även om de normala förgreningsreglerna gäller inom det. Till exempel:

    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
    

Ett lambda-uttryck motsvarar ungefär en anonym metod som deklarerats för den innehållande typen. Det första exemplet motsvarar ungefär följande:

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

Nedläggningar

Lambda-uttryck har åtkomst till alla variabler i omfånget, inklusive lokala variabler eller parametrar som definierats i den innehållande metoden och lambda-uttryck. När ett lambda-uttryck refererar till en lokal variabel eller parameter avbildar lambda-uttrycket variabeln som refereras till i en stängning. En stängning är ett objekt som finns på heapen i stället för på stacken, och när en variabel registreras omdirigeras alla referenser till variabeln till stängningen. Detta gör det möjligt för lambda-uttryck att fortsätta referera till lokala variabler och parametrar även efter att den innehållande metoden har slutförts. Till exempel:

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

motsvarar ungefär:

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

En stängning samlar in en ny kopia av en lokal variabel varje gång den anger blocket där den lokala variabeln deklareras, men den nya kopian initieras med värdet för den tidigare kopian, om någon. Till exempel:

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

Utskrifter

1 2 3 4 5 6 7 8 9 10

Istället för

9 9 9 9 9 9 9 9 9 9

Eftersom stängningar måste initieras när du anger ett block, tillåts det inte att GoTo ingå i ett block med en stängning utanför blocket, även om det tillåts att Resume ingå i ett block med en stängning. Till exempel:

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

Eftersom de inte kan fångas in i en stängning kan inte följande visas inuti ett lambda-uttryck:

  • Referensparametrar.

  • Instansuttryck (Me, MyClass, MyBase), om typen av Me inte är en klass.

Medlemmarna i ett anonymt typskapandeuttryck, om lambda-uttrycket är en del av uttrycket. Till exempel:

' Error: Lambda cannot refer to anonymous type field
Dim x = New With { .a = 12, .b = Function() .a }

ReadOnly instansvariabler i instanskonstruktorer eller ReadOnly delade variabler i delade konstruktorer där variablerna används i en icke-värdekontext. Till exempel:

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

Frågeuttryck

Ett frågeuttryck är ett uttryck som tillämpar en serie frågeoperatorer på elementen i en frågebar samling. Följande uttryck tar till exempel en samling Customer objekt och returnerar namnen på alla kunder i delstaten Washington:

Dim names = _
    From cust In Customers _
    Where cust.State = "WA" _
    Select cust.Name

Ett frågeuttryck måste börja med en From eller en Aggregate operator och kan sluta med valfri frågeoperator. Resultatet av ett frågeuttryck klassificeras som ett värde. resultattypen för uttrycket beror på resultattypen för den sista frågeoperatorn i uttrycket.

QueryExpression
    : FromOrAggregateQueryOperator QueryOperator*
    ;

FromOrAggregateQueryOperator
    : FromQueryOperator
    | AggregateQueryOperator
    ;

QueryOperator
    : FromQueryOperator
    | AggregateQueryOperator
    | SelectQueryOperator
    | DistinctQueryOperator
    | WhereQueryOperator
    | OrderByQueryOperator
    | PartitionQueryOperator
    | LetQueryOperator
    | GroupByQueryOperator
    | JoinOrGroupJoinQueryOperator
    ;

JoinOrGroupJoinQueryOperator
    : JoinQueryOperator
    | GroupJoinQueryOperator
    ;

Intervallvariabler

Vissa frågeoperatorer introducerar en särskild typ av variabel som kallas för en intervallvariabel. Intervallvariabler är inte verkliga variabler. I stället representerar de de enskilda värdena under utvärderingen av frågan över indatasamlingarna.

CollectionRangeVariableDeclarationList
    : CollectionRangeVariableDeclaration ( Comma CollectionRangeVariableDeclaration )*
    ;

CollectionRangeVariableDeclaration
    : Identifier ( 'As' TypeName )? 'In' LineTerminator? Expression
    ;

ExpressionRangeVariableDeclarationList
    : ExpressionRangeVariableDeclaration ( Comma ExpressionRangeVariableDeclaration )*
    ;

ExpressionRangeVariableDeclaration
    : Identifier ( 'As' TypeName )? Equals Expression
    ;

Intervallvariabler är begränsade från introduktionen av frågeoperatorn till slutet av ett frågeuttryck eller till en frågeoperator som den som Select döljer dem. I följande fråga kan du till exempel

Dim waCusts = _
    From cust As Customer In Customers _
    Where cust.State = "WA"

From frågeoperatorn introducerar en intervallvariabel cust som skrivs som Customer representerar varje kund i Customers samlingen. Följande Where frågeoperator refererar sedan till intervallvariabeln cust i filteruttrycket för att avgöra om en enskild kund ska filtreras bort från den resulterande samlingen.

Det finns två typer av intervallvariabler: variabler för samlingsintervall och uttrycksintervallvariabler. Samlingsintervallvariabler tar sina värden från elementen i de samlingar som efterfrågas. Samlingsuttrycket i en variabeldeklaration för samlingsintervall måste klassificeras som ett värde vars typ är frågebar. Om typen av en samlingsintervallvariabel utelämnas härleds den till elementtypen för samlingsuttrycket, eller Object om samlingsuttrycket inte har någon elementtyp (dvs. endast definierar en Cast metod). Om samlingsuttrycket inte är frågebart (dvs. elementtypen för samlingen kan inte härledas) resulterar ett kompileringsfel.

En uttrycksintervallvariabel är en intervallvariabel vars värde beräknas av ett uttryck i stället för en samling. I följande exempel Select introducerar frågeoperatorn en uttrycksintervallvariabel med namnet cityState beräknad från två fält:

Dim cityStates = _
    From cust As Customer In Customers _
    Select cityState = cust.City & "," & cust.State _
    Where cityState.Length() < 10

En uttrycksintervallvariabel krävs inte för att referera till en annan intervallvariabel, även om en sådan variabel kan vara av tvivelaktigt värde. Uttrycket som tilldelats en uttrycksintervallvariabel måste klassificeras som ett värde och måste implicit konverteras till typen av intervallvariabel, om det anges.

Endast i en Let-operator kan en uttrycksintervallvariabel ha sin typ angiven. I andra operatorer, eller om dess typ inte har angetts, används slutsatsdragning av lokal variabeltyp för att fastställa typen av intervallvariabel.

En intervallvariabel måste följa reglerna för att deklarera lokala variabler när det gäller skuggning. Därför kan en intervallvariabel inte dölja namnet på en lokal variabel eller parameter i den omslutande metoden eller en annan intervallvariabel (såvida inte frågeoperatorn specifikt döljer alla aktuella intervallvariabler i omfånget).

Frågebara typer

Frågeuttryck implementeras genom att uttrycket översätts till anrop till välkända metoder för en samlingstyp. Dessa väldefinierade metoder definierar elementtypen för den frågebara samlingen samt de resultattyper av frågeoperatorer som körs i samlingen. Varje frågeoperator anger den metod eller de metoder som frågeoperatorn vanligtvis översätts till, även om den specifika översättningen är implementeringsberoende. Metoderna anges i specifikationen med ett allmänt format som ser ut så här:

Function Select(selector As Func(Of T, R)) As CR

Följande gäller för metoderna:

  • Metoden måste vara en instans eller tilläggsmedlem av samlingstypen och måste vara tillgänglig.

  • Metoden kan vara generisk, förutsatt att det är möjligt att härleda alla typargument.

  • Metoden kan vara överbelastad, i vilket fall överbelastningsmatchning används för att fastställa exakt vilken metod som ska användas.

  • En annan ombudstyp kan användas i stället för ombudstypen Func , förutsatt att den har samma signatur, inklusive returtyp, som matchande Func typ.

  • Typen System.Linq.Expressions.Expression(Of D) kan användas i stället för ombudstypen Func , förutsatt att det D är en ombudstyp som har samma signatur, inklusive returtyp, som matchningstyp Func .

  • Typen T representerar elementtypen för indatasamlingen. Alla metoder som definieras av en samlingstyp måste ha samma typ av indataelement för att samlingstypen ska vara frågebar.

  • Typen S representerar elementtypen för den andra indatasamlingen när det gäller frågeoperatorer som utför kopplingar.

  • Typen K representerar en nyckeltyp för frågeoperatorer som har en uppsättning intervallvariabler som fungerar som nycklar.

  • Typen N representerar en typ som används som en numerisk typ (även om den fortfarande kan vara en användardefinierad typ och inte en inbyggd numerisk typ).

  • Typen B representerar en typ som kan användas i ett booleskt uttryck.

  • Typen R representerar elementtypen för resultatsamlingen, om frågeoperatorn skapar en resultatsamling. R beror på antalet intervallvariabler i omfånget när frågeoperatorn avslutas. Om en enskild intervallvariabel finns i omfånget är det R typen av intervallvariabel. I exemplet

    Dim custNames = From c In Customers
                    Select c.Name
    

    resultatet av frågan blir en samlingstyp med en elementtyp av String. Om flera intervallvariabler finns i omfånget är det R en anonym typ som innehåller alla intervallvariabler i omfånget som Key fält. I exemplet:

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

    resultatet av frågan blir en samlingstyp med en elementtyp av en anonym typ med en skrivskyddad egenskap med namnet Name typ String och en skrivskyddad egenskap med namnet ProductName av typen String.

    I ett frågeuttryck är anonyma typer som genereras för att innehålla intervallvariabler transparenta, vilket innebär att intervallvariabler alltid är tillgängliga utan kvalificering. I föregående exempel kan till exempel intervallvariabler c och o nås utan kvalificering i Select frågeoperatorn, även om indatasamlingens elementtyp var en anonym typ.

  • Typen CX representerar en samlingstyp, inte nödvändigtvis indatasamlingstypen, vars elementtyp är någon typ X.

En frågebar samlingstyp måste uppfylla något av följande villkor, i prioritetsordning:

  • Den måste definiera en överensstämmelsemetod Select .

  • Den måste ha någon av följande metoder

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

    som kan anropas för att hämta en frågebar samling. Om båda metoderna tillhandahålls AsQueryable föredras framför AsEnumerable.

  • Den måste ha en metod

    Function Cast(Of T)() As CT
    

    som kan anropas med typen av intervallvariabel för att skapa en frågebar samling.

Eftersom det inte går att bestämma elementtypen för en samling oberoende av en faktisk metodanrop kan det inte fastställas tillämpligheten för specifika metoder. När du fastställer elementtypen för en samling om det finns instansmetoder som matchar välkända metoder ignoreras därför alla tilläggsmetoder som matchar välkända metoder.

Översättning av frågeoperator sker i den ordning frågeoperatorerna förekommer i uttrycket. Det är inte nödvändigt att ett samlingsobjekt implementerar alla metoder som krävs av alla frågeoperatorer, även om varje samlingsobjekt åtminstone måste ha stöd Select för frågeoperatorn. Om det inte finns någon nödvändig metod uppstår ett kompileringsfel. Vid bindning av välkända metodnamn ignoreras icke-metoder för flera arv i gränssnitt och tilläggsmetodbindning, även om skuggningssemantik fortfarande gäller. Till exempel:

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

Standardfrågaindexerare

Varje frågebar samlingstyp vars elementtyp är T och inte redan har en standardegenskap anses ha en standardegenskap för följande allmänna formulär:

Public ReadOnly Default Property Item(index As Integer) As T
    Get
        Return Me.ElementAtOrDefault(index)
    End Get
End Property

Standardegenskapen kan bara refereras till med hjälp av standardsyntaxen för egenskapsåtkomst. Standardegenskapen kan inte refereras till med namn. Till exempel:

Dim customers As IEnumerable(Of Customer) = ...
Dim customerThree = customers(2)

' Error, no such property
Dim customerFour = customers.Item(4)

Om samlingstypen inte har någon ElementAtOrDefault medlem uppstår ett kompileringsfel.

Från frågeoperator

Frågeoperatorn From introducerar en samlingsintervallvariabel som representerar de enskilda medlemmarna i en samling som ska frågas.

FromQueryOperator
    : LineTerminator? 'From' LineTerminator? CollectionRangeVariableDeclarationList
    ;

Till exempel frågeuttrycket:

From c As Customer In Customers ...

kan ses som likvärdigt med

For Each c As Customer In Customers
        ...
Next c

När en From frågeoperator deklarerar flera samlingsintervallvariabler eller inte är den första From frågeoperatorn i frågeuttrycket , korssluts varje ny samlingsintervallvariabel till den befintliga uppsättningen intervallvariabler. Resultatet är att frågan utvärderas över korsprodukten av alla element i de anslutna samlingarna. Till exempel uttrycket:

From c In Customers _
From e In Employees _
...

kan betraktas som likvärdigt med:

For Each c In Customers
    For Each e In Employees
            ...
    Next e
Next c

och motsvarar exakt:

From c In Customers, e In Employees ...

Intervallvariablerna som introducerades i tidigare frågeoperatorer kan användas i en senare From frågeoperator. I följande frågeuttryck refererar till exempel den andra From frågeoperatorn till värdet för den första intervallvariabeln:

From c As Customer In Customers _
From o As Order In c.Orders _
Select c.Name, o

Flera intervallvariabler i en From frågeoperator eller flera From frågeoperatorer stöds bara om samlingstypen innehåller en eller båda av följande metoder:

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

Koden

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs, y In ys ...

översätts i allmänhet till

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

Observera. From är inte ett reserverat ord.

Anslut till frågeoperator

Frågeoperatorn Join kopplar samman befintliga intervallvariabler med en ny samlingsintervallvariabel, vilket skapar en enda samling vars element har kopplats samman baserat på ett likhetsuttryck.

JoinQueryOperator
    : LineTerminator? 'Join' LineTerminator? CollectionRangeVariableDeclaration
      JoinOrGroupJoinQueryOperator? LineTerminator? 'On' LineTerminator? JoinConditionList
    ;

JoinConditionList
    : JoinCondition ( 'And' LineTerminator? JoinCondition )*
    ;

JoinCondition
    : Expression 'Equals' LineTerminator? Expression
    ;

Till exempel:

Dim customersAndOrders = _
    From cust In Customers _
    Join ord In Orders On cust.ID Equals ord.CustomerID

Likhetsuttrycket är mer begränsat än ett reguljärt likhetsuttryck:

  • Båda uttrycken måste klassificeras som ett värde.

  • Båda uttrycken måste referera till minst en intervallvariabel.

  • Intervallvariabeln som deklareras i kopplingsfrågaoperatorn måste refereras till av ett av uttrycken och uttrycket får inte referera till några andra intervallvariabler.

Om typerna av de två uttrycken inte är av exakt samma typ,

  • Om likhetsoperatorn definieras för de två typerna konverteras båda uttrycken implicit till den, och det är inte Object, och konverterar sedan båda uttrycken till den typen.

  • Om det annars finns en dominerande typ som båda uttrycken kan konverteras implicit till konverterar du båda uttrycken till den typen.

  • Annars uppstår ett kompileringsfel.

Uttrycken jämförs med hash-värden (dvs. genom att anropa GetHashCode()) i stället för att använda likhetsoperatorer för effektivitet. En Join frågeoperator kan utföra flera kopplingar eller likhetsvillkor i samma operator. En Join frågeoperator stöds endast om samlingstypen innehåller en metod:

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

Koden

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs _
            Join y In ys On x Equals y _
            ...

översätts i allmänhet till

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

Obs!JoinOn och Equals är inte reserverade ord.

Låt frågeoperator

Frågeoperatorn Let introducerar en uttrycksintervallvariabel. Detta gör det möjligt att beräkna ett mellanliggande värde en gång som ska användas flera gånger i senare frågeoperatorer.

LetQueryOperator
    : LineTerminator? 'Let' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

Till exempel:

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 betraktas som likvärdigt med:

For Each o In Orders
    Dim tax = o.Price * 0.088
    ...
Next o

En Let frågeoperator stöds endast om samlingstypen innehåller en metod:

Function Select(selector As Func(Of T, R)) As CR

Koden

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Let y = x * 10 _
            ...

översätts i allmänhet till

Dim xs() As Integer = ...
Dim zs = _
    xs.Select(Function(x As Integer) New With {x, .y = x * 10})...

Välj frågeoperator

Frågeoperatorn Select är som Let frågeoperatorn i och med att den introducerar variabler för uttrycksintervall. En frågeoperator döljer dock Select de tillgängliga intervallvariablerna i stället för att lägga till dem. Dessutom härleds alltid typen av en uttrycksintervallvariabel som introduceras av en Select frågeoperator med hjälp av regler för inferens av lokal variabeltyp. Det går inte att ange en explicit typ och om ingen typ kan härledas uppstår ett kompileringsfel.

SelectQueryOperator
    : LineTerminator? 'Select' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

I frågan till exempel:

Dim smiths = _
    From cust In Customers _
    Select name = cust.name _
    Where name.EndsWith("Smith")

Where frågeoperatorn har bara åtkomst till name intervallvariabeln som introducerades av operatornSelect. Om operatorn Where hade försökt referera custtill skulle ett kompileringsfel ha uppstått.

I stället för att uttryckligen ange namnen på intervallvariablerna kan en Select frågeoperator härleda namnen på intervallvariablerna med samma regler som uttryck för skapande av anonyma objekt. Till exempel:

Dim custAndOrderNames = _
      From cust In Customers, ord In cust.Orders _
      Select cust.name, ord.ProductName _
        Where name.EndsWith("Smith")

Om namnet på intervallvariabeln inte anges och ett namn inte kan härledas uppstår ett kompileringsfel. Select Om frågeoperatorn bara innehåller ett enda uttryck uppstår inget fel om det inte går att härleda ett namn på intervallvariabeln, men intervallvariabeln är namnlös. Till exempel:

Dim custAndOrderNames = _
      From cust In Customers, ord In cust.Orders _
      Select cust.Name & " bought " & ord.ProductName _
        Take 10

Om det finns en tvetydighet i en Select frågeoperator mellan att tilldela ett namn till en intervallvariabel och ett likhetsuttryck, föredras namntilldelningen. Till exempel:

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)

Varje uttryck i Select frågeoperatorn måste klassificeras som ett värde. En Select frågeoperator stöds endast om samlingstypen innehåller en metod:

Function Select(selector As Func(Of T, R)) As CR

Koden

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Select x, y = x * 10 _
            ...

översätts i allmänhet till

Dim xs() As Integer = ...
Dim zs = _
    xs.Select(Function(x As Integer) New With {x, .y = x * 10})...

Distinkt frågeoperator

Frågeoperatorn Distinct begränsar endast värdena i en samling till värden med distinkta värden, vilket bestäms genom att jämföra elementtypen för likhet.

DistinctQueryOperator
    : LineTerminator? 'Distinct' LineTerminator?
    ;

Till exempel frågan:

Dim distinctCustomerPrice = _
    From cust In Customers, ord In cust.Orders _
    Select cust.Name, ord.Price _
    Distinct

returnerar endast en rad för varje distinkt parkoppling av kundnamn och orderpris, även om kunden har flera beställningar med samma pris. En Distinct frågeoperator stöds endast om samlingstypen innehåller en metod:

Function Distinct() As CT

Koden

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Distinct _
            ...

översätts i allmänhet till

Dim xs() As Integer = ...
Dim zs = xs.Distinct()...

Observera. Distinct är inte ett reserverat ord.

Där frågeoperator

Frågeoperatorn Where begränsar värdena i en samling till de som uppfyller ett visst villkor.

WhereQueryOperator
    : LineTerminator? 'Where' LineTerminator? BooleanExpression
    ;

En Where frågeoperator tar ett booleskt uttryck som utvärderas för varje uppsättning intervallvariabelvärden. Om värdet för uttrycket är sant visas värdena i utdatasamlingen, annars hoppas värdena över. Till exempel frågeuttrycket:

From cust In Customers, ord In Orders _
Where cust.ID = ord.CustomerID _
...

kan betraktas som ekvivalent med den kapslade loopen

For Each cust In Customers
    For Each ord In Orders
            If cust.ID = ord.CustomerID Then
                ...
            End If
    Next ord
Next cust

En Where frågeoperator stöds endast om samlingstypen innehåller en metod:

Function Where(predicate As Func(Of T, B)) As CT

Koden

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Where x < 10 _
            ...

översätts i allmänhet till

Dim xs() As Integer = ...
Dim zs = _
    xs.Where(Function(x As Integer) x < 10)...

Observera. Where är inte ett reserverat ord.

Partitionsfrågaoperatorer

PartitionQueryOperator
    : LineTerminator? 'Take' LineTerminator? Expression
    | LineTerminator? 'Take' 'While' LineTerminator? BooleanExpression
    | LineTerminator? 'Skip' LineTerminator? Expression
    | LineTerminator? 'Skip' 'While' LineTerminator? BooleanExpression
    ;

Frågeoperatorn Take resulterar i de första n elementen i en samling. När den används med While modifieraren resulterar operatorn Take i de första n elementen i en samling som uppfyller ett booleskt uttryck. Operatorn Skip hoppar över de första n elementen i en samling och returnerar sedan resten av samlingen. När den används tillsammans med While modifieraren hoppar operatorn över de första n elementen Skip i en samling som uppfyller ett booleskt uttryck och returnerar sedan resten av samlingen. Uttrycken i en Take eller Skip frågeoperatorn måste klassificeras som ett värde.

En Take frågeoperator stöds endast om samlingstypen innehåller en metod:

Function Take(count As N) As CT

En Skip frågeoperator stöds endast om samlingstypen innehåller en metod:

Function Skip(count As N) As CT

En Take While frågeoperator stöds endast om samlingstypen innehåller en metod:

Function TakeWhile(predicate As Func(Of T, B)) As CT

En Skip While frågeoperator stöds endast om samlingstypen innehåller en metod:

Function SkipWhile(predicate As Func(Of T, B)) As CT

Koden

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Skip 10 _
            Take 5 _
            Skip While x < 10 _
            Take While x > 5 _
            ...

översätts i allmänhet till

Dim xs() As Integer = ...
Dim zs = _
    xs.Skip(10). _
        Take(5). _
        SkipWhile(Function(x) x < 10). _
        TakeWhile(Function(x) x > 5)...

Observera. Take och Skip är inte reserverade ord.

Ordning efter frågeoperator

Frågeoperatorn Order By beställer de värden som visas i intervallvariablerna.

OrderByQueryOperator
    : LineTerminator? 'Order' 'By' LineTerminator? OrderExpressionList
    ;

OrderExpressionList
    : OrderExpression ( Comma OrderExpression )*
    ;

OrderExpression
    : Expression Ordering?
    ;

Ordering
    : 'Ascending' | 'Descending'
    ;

En Order By frågeoperator tar uttryck som anger de nyckelvärden som ska användas för att sortera iterationsvariablerna. Följande fråga returnerar till exempel produkter sorterade efter pris:

Dim productsByPrice = _
    From p In Products _
    Order By p.Price _
    Select p.Name

En ordning kan markeras som Ascending, i vilket fall mindre värden kommer före större värden, eller Descending, i vilket fall större värden kommer före mindre värden. Standardvärdet för en beställning om ingen har angetts är Ascending. Följande fråga returnerar till exempel produkter sorterade efter pris med den dyraste produkten först:

Dim productsByPriceDesc = _
    From p In Products _
    Order By p.Price Descending _
    Select p.Name

Frågeoperatorn Order By kan ange flera uttryck för beställning, i vilket fall samlingen sorteras på ett kapslat sätt. Följande fråga beställer till exempel kunder efter delstat, sedan efter stad inom varje delstat och sedan efter postnummer i varje stad:

Dim customersByLocation = _
    From c In Customers _
    Order By c.State, c.City, c.ZIP _
    Select c.Name, c.State, c.City, c.ZIP

Uttrycken i en Order By frågeoperator måste klassificeras som ett värde. En Order By frågeoperator stöds endast om samlingstypen innehåller en eller båda av följande metoder:

Function OrderBy(keySelector As Func(Of T, K)) As CT
Function OrderByDescending(keySelector As Func(Of T, K)) As CT

Returtypen CT måste vara en ordnad samling. En ordnad samling är en samlingstyp som innehåller en eller båda metoderna:

Function ThenBy(keySelector As Func(Of T, K)) As CT
Function ThenByDescending(keySelector As Func(Of T, K)) As CT

Koden

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Order By x Ascending, x Mod 2 Descending _
            ...

översätts i allmänhet till

Dim xs() As Integer = ...
Dim zs = _
    xs.OrderBy(Function(x) x).ThenByDescending(Function(x) x Mod 2)...

Observera. Eftersom frågeoperatorer bara mappar syntax till metoder som implementerar en viss frågeåtgärd, styrs inte orderbevaring av språket och bestäms av implementeringen av själva operatorn. Detta liknar användardefinierade operatorer eftersom implementeringen för att överbelasta additionsoperatorn för en användardefinierad numerisk typ kanske inte utför något som liknar ett tillägg. För att bevara förutsägbarheten rekommenderar vi naturligtvis inte att du implementerar något som inte matchar användarnas förväntningar.

Observera. Order och By är inte reserverade ord.

Gruppera efter frågeoperator

Frågeoperatorn Group By grupperar intervallvariablerna i omfånget baserat på ett eller flera uttryck och skapar sedan nya intervallvariabler baserat på dessa grupper.

GroupByQueryOperator
    : LineTerminator? 'Group' ( LineTerminator? ExpressionRangeVariableDeclarationList )?
      LineTerminator? 'By' LineTerminator? ExpressionRangeVariableDeclarationList
      LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

Följande fråga grupperar till exempel alla kunder efter Stateoch beräknar sedan antalet och den genomsnittliga åldern för varje grupp:

Dim averageAges = _
    From cust In Customers _
    Group By cust.State _
    Into Count(), Average(cust.Age)

Frågeoperatorn Group By har tre satser: den valfria Group satsen, By -satsen och Into -satsen. Satsen Group har samma syntax och effekt som en Select frågeoperator, förutom att den endast påverkar de intervallvariabler som är tillgängliga i Into -satsen och inte By satsen. Till exempel:

Dim averageAges = _
    From cust In Customers _
    Group cust.Age By cust.State _
    Into Count(), Average(Age)

Satsen By deklarerar uttrycksintervallvariabler som används som nyckelvärden i grupperingsåtgärden. Into Satsen tillåter deklaration av uttrycksintervallvariabler som beräknar sammansättningar över var och en av de grupper som bildas av By -satsen. Into I -satsen kan uttrycksintervallvariabeln bara tilldelas ett uttryck som är en metodanrop av en aggregeringsfunktion. En mängdfunktion är en funktion i samlingstypen för gruppen (som kanske inte nödvändigtvis är samma samlingstyp som den ursprungliga samlingen) som ser ut som någon av följande metoder:

Function _name_() As _type_
Function _name_(selector As Func(Of T, R)) As R

Om en aggregeringsfunktion tar ett ombudsargument kan anropsuttrycket ha ett argumentuttryck som måste klassificeras som ett värde. Argumentuttrycket kan använda de intervallvariabler som finns i omfånget. inom anropet till en mängdfunktion representerar dessa intervallvariabler värdena i den grupp som bildas, inte alla värden i samlingen. I det ursprungliga exemplet i det här avsnittet Average beräknar funktionen till exempel genomsnittet av kundernas ålder per tillstånd i stället för för alla kunder tillsammans.

Alla samlingstyper anses ha den sammanställda funktionen Group definierad på den, vilket inte tar några parametrar och helt enkelt returnerar gruppen. Andra standardaggregeringsfunktioner som en samlingstyp kan tillhandahålla är:

Count och LongCount, som returnerar antalet element i gruppen eller antalet element i gruppen som uppfyller ett booleskt uttryck. Count och LongCount stöds endast om samlingstypen innehåller någon av metoderna:

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, som returnerar summan av ett uttryck för alla element i gruppen. Sum stöds endast om samlingstypen innehåller någon av metoderna:

Function Sum() As N
Function Sum(selector As Func(Of T, N)) As N

Min som returnerar minimivärdet för ett uttryck för alla element i gruppen. Min stöds endast om samlingstypen innehåller någon av metoderna:

Function Min() As N
Function Min(selector As Func(Of T, N)) As N

Max, som returnerar det maximala värdet för ett uttryck för alla element i gruppen. Max stöds endast om samlingstypen innehåller någon av metoderna:

Function Max() As N
Function Max(selector As Func(Of T, N)) As N

Average, som returnerar medelvärdet av ett uttryck för alla element i gruppen. Average stöds endast om samlingstypen innehåller någon av metoderna:

Function Average() As N
Function Average(selector As Func(Of T, N)) As N

Any, som avgör om en grupp innehåller medlemmar eller om ett booleskt uttryck är sant för något element i gruppen. Any returnerar ett värde som kan användas i ett booleskt uttryck och stöds endast om samlingstypen innehåller någon av metoderna:

Function Any() As B
Function Any(predicate As Func(Of T, B)) As B

All, som avgör om ett booleskt uttryck är sant för alla element i gruppen. All returnerar ett värde som kan användas i ett booleskt uttryck och stöds endast om samlingstypen innehåller en metod:

Function All(predicate As Func(Of T, B)) As B

Efter en Group By frågeoperator är intervallvariablerna som tidigare fanns i omfånget dolda och de intervallvariabler som introducerades av By satserna och Into är tillgängliga. En Group By frågeoperator stöds endast om samlingstypen innehåller metoden:

Function GroupBy(keySelector As Func(Of T, K), _
                      resultSelector As Func(Of K, CT, R)) As CR

Intervallvariabeldeklarationer i Group -satsen stöds endast om samlingstypen innehåller metoden:

Function GroupBy(keySelector As Func(Of T, K), _
                      elementSelector As Func(Of T, S), _
                      resultSelector As Func(Of K, CS, R)) As CR

Koden

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

översätts i allmänhet till

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

Note.Group, By, och Into är inte reserverade ord.

Aggregera frågeoperator

Frågeoperatorn Aggregate utför en liknande funktion som operatorn Group By , förutom att den tillåter aggregering över grupper som redan har skapats. Eftersom gruppen redan har skapats Into döljer inte satsen för en Aggregate frågeoperator intervallvariablerna i omfånget (på det här sättet Aggregate liknar det mer en Let, och Group By liknar mer en Select).

AggregateQueryOperator
    : LineTerminator? 'Aggregate' LineTerminator? CollectionRangeVariableDeclaration QueryOperator*
      LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

Följande fråga aggregerar till exempel summan av alla beställningar som görs av kunder i Washington:

Dim orderTotals = _
    From cust In Customers _
    Where cust.State = "WA" _
    Aggregate order In cust.Orders _
    Into Sum(order.Total)

Resultatet av den här frågan är en samling vars elementtyp är en anonym typ med en egenskap med namnet cust skrivet som Customer och en egenskap med Integernamnet Sum typ som .

Till skillnad från Group Bykan ytterligare frågeoperatorer placeras mellan Aggregate - och-satserna Into . Mellan en Aggregate sats och slutet av Into satsen kan alla intervallvariabler i omfånget Aggregate , inklusive de som deklareras av satsen, användas. Följande fråga aggregerar till exempel summan av alla beställningar som gjorts av kunder i Washington före 2006:

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)

Operatorn Aggregate kan också användas för att starta ett frågeuttryck. I det här fallet blir resultatet av frågeuttrycket det enda värde som beräknas av Into -satsen. Följande fråga beräknar till exempel summan av alla ordersummor före den 1 januari 2006:

Dim ordersTotal = _
    Aggregate order In Orders _
    Where order.Date <= #01/01/2006# _
    Into Sum(order.Total)

Resultatet av frågan är ett enda Integer värde. En Aggregate frågeoperator är alltid tillgänglig (även om aggregeringsfunktionen också måste vara tillgänglig för att uttrycket ska vara giltigt). Koden

Dim xs() As Integer = ...
Dim zs = _
    Aggregate x In xs _
    Where x < 5 _
    Into Sum()

översätts i allmänhet till

Dim xs() As Integer = ...
Dim zs = _
    xs.Where(Function(x) x < 5).Sum()

Observera.  Aggregate och Into är inte reserverade ord.

Frågeoperator för gruppkoppling

Frågeoperatorn Group Join kombinerar funktionerna för Join och Group By frågeoperatorerna till en enda operator. Group Join sammanfogar två samlingar baserat på matchande nycklar som extraherats från elementen och grupperar alla element på höger sida av kopplingen som matchar ett visst element på vänster sida av kopplingen. Därför genererar operatorn en uppsättning hierarkiska resultat.

GroupJoinQueryOperator
    : LineTerminator? 'Group' 'Join' LineTerminator? CollectionRangeVariableDeclaration
      JoinOrGroupJoinQueryOperator? LineTerminator? 'On' LineTerminator? JoinConditionList
      LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

Följande fråga skapar till exempel element som innehåller en enskild kunds namn, en grupp med alla deras beställningar och den totala mängden av alla dessa beställningar:

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

Resultatet av frågan är en samling vars elementtyp är en anonym typ med tre egenskaper: Name, skrivs som , Orders skrivs som Stringen samling vars elementtyp är Order, och OrdersTotal, skrivs som Integer. En Group Join frågeoperator stöds endast om samlingstypen innehåller metoden:

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

Koden

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

översätts i allmänhet till

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

Note.Group, Join, och Into är inte reserverade ord.

Villkorsstyrda uttryck

Ett villkorsuttryck If testar ett uttryck och returnerar ett värde.

ConditionalExpression
    : 'If' OpenParenthesis BooleanExpression Comma Expression Comma Expression CloseParenthesis
    | 'If' OpenParenthesis Expression Comma Expression CloseParenthesis
    ;

IIF Till skillnad från körningsfunktionen utvärderar dock ett villkorsuttryck endast dess operander om det behövs. Uttrycket utlöser till exempel If(c Is Nothing, c.Name, "Unknown") inte ett undantag om värdet c för är Nothing. Villkorsuttrycket har två former: en som tar två operander och en som tar tre operander.

Om tre operander anges måste alla tre uttrycken klassificeras som värden och den första operanden måste vara ett booleskt uttryck. Om resultatet av uttrycket är sant blir det andra uttrycket resultatet av operatorn, annars blir det tredje uttrycket resultatet av operatorn. Resultattypen för uttrycket är den dominerande typen mellan typerna av det andra och tredje uttrycket. Om det inte finns någon dominerande typ uppstår ett kompileringsfel.

Om två operander anges måste båda operanderna klassificeras som värden och den första operanden måste vara antingen en referenstyp eller en nullbar värdetyp. Uttrycket If(x, y) utvärderas sedan som om var uttrycket If(x IsNot Nothing, x, y), med två undantag. För det första utvärderas det första uttrycket bara en gång, och för det andra, om den andra operandens typ är en värdetyp som inte är nullbar och den första operandens typ är, ? tas den bort från typen av den första operanden när den dominerande typen för uttryckets resultattyp bestäms. Till exempel:

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

Om en operand är Nothingi båda uttrycksformerna används inte dess typ för att fastställa den dominerande typen. När det gäller uttrycket If(<expression>, Nothing, Nothing)anses den dominerande typen vara Object.

XML-literaluttryck

Ett XML-literaluttryck representerar ett XML-värde (eXtensible Markup Language) 1.0.

XMLLiteralExpression
    : XMLDocument
    | XMLElement
    | XMLProcessingInstruction
    | XMLComment
    | XMLCDATASection
    ;

Resultatet av ett XML-literaluttryck är ett värde som skrivs som en av typerna System.Xml.Linq från namnområdet. Om typerna i namnområdet inte är tillgängliga orsakar ett XML-literaluttryck ett kompileringsfel. Värdena genereras via konstruktoranrop som översätts från XML-literaluttrycket. Till exempel koden:

Dim book As System.Xml.Linq.XElement = _
    <book title="My book"></book>

motsvarar ungefär koden:

Dim book As System.Xml.Linq.XElement = _
    New System.Xml.Linq.XElement( _
        "book", _
        New System.Xml.Linq.XAttribute("title", "My book"))

Ett XML-literaluttryck kan ha formen av ett XML-dokument, ett XML-element, en XML-bearbetningsinstruktion, en XML-kommentar eller ett CDATA-avsnitt.

Observera. Den här specifikationen innehåller bara tillräckligt med en beskrivning av XML för att beskriva beteendet för Visual Basic-språket. Mer information om XML finns på http://www.w3.org/TR/REC-xml/.

Lexikala regler

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

XML-literaluttryck tolkas med hjälp av lexikala regler för XML i stället för de lexikala reglerna för vanlig Visual Basic-kod. De två regeluppsättningarna skiljer sig vanligtvis åt på följande sätt:

  • Tomt utrymme är betydande i XML. Det innebär att grammatiken för XML-literaluttryck uttryckligen anger var tomt utrymme tillåts. Tomt utrymme bevaras inte, förutom när det inträffar i kontexten för teckendata i ett element. Till exempel:

    ' The following element preserves no whitespace
    Dim e1 = _
        <customer>
            <name>Bob</>
        </>
    
    ' The following element preserves all of the whitespace
    Dim e2 = _
        <customer>
            Bob
        </>
    
  • XML-slutpunkts-blanksteg normaliseras enligt XML-specifikationen.

  • XML är skiftlägeskänsligt. Nyckelord måste matcha höljet exakt, annars uppstår ett kompileringsfel.

  • Radavgränsare betraktas som tomt utrymme i XML. Därför behövs inga radfortsättningstecken i XML-literaluttryck.

  • XML accepterar inte tecken med full bredd. Om tecken med full bredd används uppstår ett kompileringsfel.

Inbäddade uttryck

XML-literaluttryck kan innehålla inbäddade uttryck. Ett inbäddat uttryck är ett Visual Basic-uttryck som utvärderas och används för att fylla i ett eller flera värden på platsen för inbäddade uttryck.

XMLEmbeddedExpression
    : '<' '%' '=' LineTerminator? Expression LineTerminator? '%' '>'
    ;

Följande kod placerar till exempel strängen John Smith som värdet för XML-elementet:

Dim name as String = "John Smith"
Dim element As System.Xml.Linq.XElement = <customer><%= name %></customer>

Uttryck kan bäddas in i ett antal kontexter. Följande kod skapar till exempel ett element med namnet customer:

Dim name As String = "customer"
Dim element As System.Xml.Linq.XElement = <<%= name %>>John Smith</>

Varje kontext där ett inbäddat uttryck kan användas anger vilka typer som ska godkännas. När de normala lexikala reglerna för Visual Basic-kod fortfarande gäller i kontexten för uttrycksdelen av ett inbäddat uttryck, så måste till exempel radfortsättningar användas:

' Visual Basic expression uses line continuation, XML does not
Dim element As System.Xml.Linq.XElement = _
    <<%= name & _
          name %>>John 
                     Smith</>

XML-dokument

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
    ;

Ett XML-dokument resulterar i ett värde som skrivs som System.Xml.Linq.XDocument. Till skillnad från XML 1.0-specifikationen krävs XML-dokument i XML-literaluttryck för att ange XML-dokumentprologen. XML-literaluttryck utan XML-dokumentprolog tolkas som deras enskilda entitet. Till exempel:

Dim doc As System.Xml.Linq.XDocument = _
    <?xml version="1.0"?>
    <?instruction?>
    <customer>Bob</>

Dim pi As System.Xml.Linq.XProcessingInstruction = _
    <?instruction?>

Ett XML-dokument kan innehålla ett inbäddat uttryck vars typ kan vara valfri typ. Vid körning måste dock objektet uppfylla kraven för XDocument konstruktorn, annars uppstår ett körningsfel.

Till skillnad från vanlig XML stöder XML-dokumentuttryck inte DTD:er (dokumenttypdeklarationer). Dessutom ignoreras kodningsattributet, om det tillhandahålls, eftersom kodningen av Xml-literaluttrycket alltid är samma som kodningen av själva källfilen.

Observera. Även om kodningsattributet ignoreras är det fortfarande ett giltigt attribut för att kunna inkludera giltiga Xml 1.0-dokument i källkoden.

XML-element

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+ ';'
    ;

Ett XML-element resulterar i ett värde som skrivs som System.Xml.Linq.XElement. Till skillnad från vanlig XML kan XML-element utelämna namnet i den avslutande taggen och det aktuella mest kapslade elementet stängs. Till exempel:

Dim name = <name>Bob</>

Attributdeklarationer i ett XML-element resulterar i värden som skrivs som System.Xml.Linq.XAttribute. Attributvärden normaliseras enligt XML-specifikationen. När värdet för ett attribut är Nothing skapas inte attributet, så attributets värdeuttryck behöver inte kontrolleras för Nothing. Till exempel:

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-element och -attribut kan innehålla kapslade uttryck på följande platser:

Namnet på elementet, i vilket fall det inbäddade uttrycket måste vara ett värde av en typ som implicit kan konverteras till System.Xml.Linq.XName. Till exempel:

Dim name = <<%= "name" %>>Bob</>

Namnet på ett attribut för elementet, i vilket fall det inbäddade uttrycket måste vara ett värde av en typ som implicit kan konverteras till System.Xml.Linq.XName. Till exempel:

Dim name = <name <%= "length" %>="3">Bob</>

Värdet för ett attribut för elementet, i vilket fall det inbäddade uttrycket kan vara ett värde av vilken typ som helst. Till exempel:

Dim name = <name length=<%= 3 %>>Bob</>

Ett attribut för elementet, i vilket fall det inbäddade uttrycket kan vara ett värde av vilken typ som helst. Till exempel:

Dim name = <name <%= new XAttribute("length", 3) %>>Bob</>

Innehållet i elementet, i vilket fall det inbäddade uttrycket kan vara ett värde av vilken typ som helst. Till exempel:

Dim name = <name><%= "Bob" %></>

Om typen av det inbäddade uttrycket är Object()skickas matrisen som en paramarray till XElement konstruktorn.

XML-namnområden

XML-element kan innehålla XML-namnområdesdeklarationer enligt definitionen i XML-namnområden 1.0-specifikationen.

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
    ;

Begränsningarna för att definiera namnrymderna xml och xmlns framtvingas och kommer att generera kompileringsfel. XML-namnområdesdeklarationer kan inte ha ett inbäddat uttryck för värdet. det angivna värdet måste vara en strängliteral som inte är tom. Till exempel:

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

Observera. Den här specifikationen innehåller bara tillräckligt med en beskrivning av XML-namnområdet för att beskriva beteendet för visual basic-språket. Mer information om XML-namnområden finns på http://www.w3.org/TR/REC-xml-names/.

XML-element och attributnamn kan kvalificeras med namnområdesnamn. Namnrymder är bundna som i vanlig XML, med undantag för att alla namnområdesimporter som deklareras på filnivå anses deklareras i en kontext som omger deklarationen, som i sig omges av alla namnområdesimporter som deklareras av kompileringsmiljön. Om det inte går att hitta ett namnområdesnamn uppstår ett kompileringsfel. Till exempel:

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-namnområden som deklareras i ett element gäller inte för XML-literaler i inbäddade uttryck. Till exempel:

' Error: Namespace prefix 'db' is not declared
Dim customer = _
    <db:customer xmlns:db="http://example.org/database">
        <%= <db:customer>Bob</> %>
    </>

Observera. Det beror på att det inbäddade uttrycket kan vara vad som helst, inklusive ett funktionsanrop. Om funktionsanropet innehöll ett XML-literaluttryck är det inte klart om programmerare förväntar sig att XML-namnområdet ska tillämpas eller ignoreras.

XML-bearbetningsinstruktioner

En XML-bearbetningsinstruktion resulterar i ett värde som skrivs som System.Xml.Linq.XProcessingInstruction. XML-bearbetningsinstruktioner får inte innehålla inbäddade uttryck, eftersom de är giltiga syntaxer i bearbetningsinstruktionen.

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-kommentarer

En XML-kommentar resulterar i ett värde som skrivs som System.Xml.Linq.XComment. XML-kommentarer får inte innehålla inbäddade uttryck eftersom de är giltiga syntaxer i kommentaren.

XMLComment
    : '<' '!' '-' '-' XMLCommentCharacter* '-' '-' '>'
    ;

XMLCommentCharacter
    : '<Any XMLCharacter except dash (0x002D)>'
    | '-' '<Any XMLCharacter except dash (0x002D)>'
    ;

CDATA-avsnitt

Ett CDATA-avsnitt resulterar i ett värde som skrivs som System.Xml.Linq.XCData. CDATA-avsnitt kan inte innehålla inbäddade uttryck, eftersom de är giltig syntax i CDATA-avsnittet.

XMLCDATASection
    : '<' '!' ( 'CDATA' '[' XMLCDATASectionString? ']' )? '>'
    ;

XMLCDATASectionString
    : '<Any XMLString that does not contain the string "]]>">'
    ;

XML-medlemsåtkomstuttryck

Ett XML-medlemsåtkomstuttryck får åtkomst till medlemmarna i ett XML-värde.

XMLMemberAccessExpression
    : Expression '.' LineTerminator? '<' XMLQualifiedName '>'
    | Expression '.' LineTerminator? '@' LineTerminator? '<' XMLQualifiedName '>'
    | Expression '.' LineTerminator? '@' LineTerminator? IdentifierOrKeyword
    | Expression '.' '.' '.' LineTerminator? '<' XMLQualifiedName '>'
    ;

Det finns tre typer av XML-medlemsåtkomstuttryck:

  • Elementåtkomst, där ett XML-namn följer en enda punkt. Till exempel:

    Dim customer = _
        <customer>
            <name>Bob</>
        </>
    Dim customerName = customer.<name>.Value
    

    Elementåtkomstmappningar till funktionen:

    Function Elements(name As System.Xml.Linq.XName) As _
        System.Collections.Generic.IEnumerable(Of _
            System.Xml.Linq.XNode)
    

    Exemplet ovan motsvarar alltså:

    Dim customerName = customer.Elements("name").Value
    
  • Attributåtkomst, där en Visual Basic-identifierare följer en punkt och ett vid tecken, eller ett XML-namn följer en punkt och ett vid tecken. Till exempel:

    Dim customer = <customer age="30"/>
    Dim customerAge = customer.@age
    

    Attributåtkomstmappningar till funktionen:

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

    Exemplet ovan motsvarar alltså:

    Dim customerAge = customer.AttributeValue("age")
    

    Observera. Tilläggsmetoden AttributeValue (samt den relaterade tilläggsegenskapen Value) definieras för närvarande inte i någon sammansättning. Om tilläggsmedlemmarna behövs definieras de automatiskt i sammansättningen som skapas.

  • Underordnade åtkomst, där ett XML-namn följer tre punkter. Till exempel:

    Dim company = _
        <company>
            <customers>
                <customer>Bob</>
                <customer>Mary</>
                <customer>Joe</>
            </>
        </>
    Dim customers = company...<customer>
    

    Underordnade åtkomstmappningar till funktionen:

    Function Descendents(name As System.Xml.Linq.XName) As _
        System.Collections.Generic.IEnumerable(Of _
            System.Xml.Linq.XElement)
    

    Exemplet ovan motsvarar alltså:

    Dim customers = company.Descendants("customer")
    

Basuttrycket för ett XML-medlemsåtkomstuttryck måste vara ett värde och måste vara av typen:

  • Om ett element eller underordnade objekt får åtkomst, System.Xml.Linq.XContainer en härledd typ eller System.Collections.Generic.IEnumerable(Of T) en härledd typ, där T är System.Xml.Linq.XContainer eller en härledd typ.

  • Om en attributåtkomst, System.Xml.Linq.XElement en härledd typ eller System.Collections.Generic.IEnumerable(Of T) en härledd typ, där T är System.Xml.Linq.XElement eller en härledd typ.

Namn i XML-medlemsåtkomstuttryck får inte vara tomma. De kan vara namnområdeskvalificerade med hjälp av namnrymder som definieras av importer. Till exempel:

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

Blanksteg tillåts inte efter punkterna i ett XML-medlemsåtkomstuttryck eller mellan vinkelparenteserna och namnet. Till exempel:

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 >

Om typerna System.Xml.Linq i namnområdet inte är tillgängliga orsakar ett XML-medlemsåtkomstuttryck ett kompileringsfel.

Await-operator

Await-operatorn är relaterad till asynkrona metoder, som beskrivs i Avsnitt Async-metoder.

AwaitOperatorExpression
    : 'Await' Expression
    ;

Await är ett reserverat ord om den omedelbart omslutande metoden eller lambda-uttrycket där det visas har en Async modifierare, och om det Await visas efter Async den modifieraren, är det oreserverat någon annanstans. Det är också oreserverat i förprocessordirektiv. Operatorn await tillåts endast i brödtexten för en metod eller lambda-uttryck där det är ett reserverat ord. Inom den omedelbart omslutande metoden eller lambda får ett inväntningsuttryck inte förekomma i brödtexten i en eller Finally ett Catch block eller inuti brödtexten i en SyncLock -instruktion eller inuti ett frågeuttryck.

Operatorn await tar ett enda uttryck som måste klassificeras som ett värde och vars typ måste vara en väntande typ, eller Object. Om dess typ är Object skjuts all bearbetning upp till körning. En typ C sägs vara väntande om allt följande är sant:

  • C innehåller en tillgänglig instans eller tilläggsmetod med namnet GetAwaiter som inte har några argument och som returnerar någon typ E;

  • E innehåller en läsbar instans- eller tilläggsegenskap med namnet IsCompleted som inte tar några argument och har typen Boolesk.

  • E innehåller en tillgänglig instans eller tilläggsmetod med namnet GetResult som inte tar några argument.

  • E implementerar antingen System.Runtime.CompilerServices.INotifyCompletion eller ICriticalNotifyCompletion.

Om GetResult var ett Subklassificeras inväntningsuttrycket som void. Annars klassificeras await-uttrycket som ett värde och dess typ är metodens GetResult returtyp.

Här är ett exempel på en klass som kan vänta:

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

Observera. Biblioteksförfattare rekommenderas att följa mönstret att de anropar fortsättningsdelegaten på samma SynchronizationContext sätt som de OnCompleted själv anropades. Dessutom bör återupptagningsdelegaten inte köras synkront i OnCompleted metoden eftersom det kan leda till stackspill: i stället ska ombudet placeras i kö för efterföljande körning.

När kontrollflödet når en Await operator är beteendet följande.

  1. Metoden GetAwaiter för den väntande operanden anropas. Resultatet av det här anropet kallas för den som väntar.

  2. Awaiter-egenskapen hämtas IsCompleted . Om resultatet är sant:

    1. Metoden GetResult för awaiter anropas. Om GetResult var en funktion är värdet för await-uttrycket returvärdet för den här funktionen.
  3. Om egenskapen IsCompleted inte är sann:

    1. Antingen ICriticalNotifyCompletion.UnsafeOnCompleted anropas den som väntar (om inväntarens typ E implementerar ICriticalNotifyCompletion) eller INotifyCompletion.OnCompleted (annars). I båda fallen skickas ett återtagandedelegat som är associerat med den aktuella instansen av async-metoden.

    2. Kontrollpunkten för den aktuella asynkrona metodinstansen pausas och kontrollflödet återupptas i den aktuella anroparen (definieras i Avsnitt Async-metoder).

    3. Om återupptagningsdelegaten senare anropas anropas

      1. återtagandedelegaten återställer System.Threading.Thread.CurrentThread.ExecutionContext först till vad det var vid den tidpunkt OnCompleted då anropades,
      2. sedan återupptas kontrollflödet vid kontrollpunkten för asynkron metodinstansen (se Avsnitt Async-metoder),
      3. där den anropar GetResult inväntarens metod, som i 2.1 ovan.

Om await operand har typen Object skjuts det här beteendet upp till körningen:

  • Steg 1 uppnås genom att anropa GetAwaiter() utan argument. Den kan därför vid körning binda till instansmetoder som tar valfria parametrar.
  • Steg 2 utförs genom att hämta egenskapen IsCompleted() utan argument och genom att försöka utföra en inbyggd konvertering till boolesk.
  • Steg 3.a utförs genom att TryCast(awaiter, ICriticalNotifyCompletion)försöka , och om detta misslyckas så DirectCast(awaiter, INotifyCompletion).

Återupptagningsdelegaten som skickades i 3.a kan bara anropas en gång. Om det anropas mer än en gång är beteendet odefinierat.