Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
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
Nothinggenererar 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 somf()ochf(Of Integer)tolkas somf(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 ModuleEn 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:
Om måltypen är en ombudstyp tolkas lambda-metoden som argumentet till ett ombudskonstruktionsuttryck av lämplig typ.
Om måltypen är
System.Linq.Expressions.Expression(Of T), ochTär en ombudstyp, tolkas lambda-metoden som om den användes i uttrycket delegate-construction förToch 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
Sublambdas 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
Objectersä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 ModuleEn egenskapsgrupp kan omklassificeras som en egenskapsåtkomst. Egenskapsgrupputtrycket tolkas som ett indexuttryck med tomma parenteser (d.s
f. tolkas somf()).En egenskapsåtkomst kan omklassificeras som ett värde. Egenskapsåtkomstuttrycket tolkas som ett anropsuttryck för
Getegenskapens 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:
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 ochIEnumerable(Of T)matrisliteralen har en kapslingsnivå, omklassificeras matrisliteralen som ett värde av typenT().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,
Objectanvä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ärledtsObject()som typ avai version 9.0 av språket ochInteger()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
Nothingkan 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 typenObject.
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 eftersomStringkonverteringar 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
+,-ochNotunary, 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.Chrom konstantvärdet är mellan 0 och 128,Microsoft.VisualBasic.Strings.AscWom konstantsträngen inte är tom,Microsoft.VisualBasic.Strings.Ascom konstantsträngen inte är tom.
Följande konstruktioner tillåts inte i konstanta uttryck:
- Implicit bindning via en
Withkontext.
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":
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
Getaccessorn returnerar lokal variabel, och uttrycket är en del av ett anropsuttryck, en anropsinstrukation eller ettAddressOfuttryck, 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.
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:
- 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.
- 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ärEär identifieraren ochAär typargumentlistan, om någon. - Annars är resultatet exakt samma som en medlemsåtkomst i formuläret
T.E(Of A), därTär den typ som innehåller den matchande medlemmen,Eär identifieraren ochAär typargumentlistan, om någon. I det här fallet är det ett fel för identifieraren att referera till en icke-delad medlem.
Gör följande för varje kapslad namnrymd, från den innersta och gå till det yttersta namnområdet:
- 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.
- 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.
- 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ärMär standardmodulen som innehåller den matchande medlemmen,Eär identifieraren ochAär typargumentlistan, om det finns några. Om identifieraren matchar medlemmar av tillgänglig typ i mer än en standardmodul uppstår ett kompileringsfel.
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.
Om källfilen som innehåller namnreferensen har en eller flera importer:
- 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.
- 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.
- 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ärMär standardmodulen som innehåller den matchande medlemmen,Eär identifieraren ochAär typargumentlistan. om det finns några. Om identifieraren matchar medlemmar av tillgänglig typ i mer än en standardmodul uppstår ett kompileringsfel.
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.
Om kompileringsmiljön definierar en eller flera importer:
- 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.
- 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.
- 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ärMär standardmodulen som innehåller den matchande medlemmen,Eär identifieraren ochAär typargumentlistan. om det finns några. Om identifieraren matchar medlemmar av tillgänglig typ i mer än en standardmodul uppstår ett kompileringsfel.
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å
GetTypesätt kan uttrycket returnera detSystem.Typeobjekt 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:
Om
Eutelämnas ersätts uttrycket från den omedelbart innehållandeWithinstruktionen ochEmedlemsåtkomsten utförs. Om det inte finns någon innehållandeWithinstruktion uppstår ett kompileringsfel.Om
Eklassificeras som ett namnområde ellerEär nyckelordetGlobalgörs medlemssökningen i kontexten för det angivna namnområdet. OmIä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.Om
Eär en typ eller ett uttryck som klassificeras som en typ görs medlemssökningen i kontexten för den angivna typen. OmIär namnet på en tillgänglig medlem iEE.Iutvärderas och klassificeras följande:- Om
Iär nyckelordetNewochEinte är en uppräkning uppstår ett kompileringsfel. - Om
Iidentifierar en typ med samma antal typparametrar som angavs i typargumentlistan, om någon, blir resultatet den typen. - Om
Iidentifierar en eller flera metoder är resultatet en metodgrupp med den associerade typargumentlistan och inget associerat måluttryck. - Om
Iidentifierar en eller flera egenskaper och ingen typargumentlista angavs är resultatet en egenskapsgrupp utan associerat måluttryck. - Om
Iidentifierar 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 variabelnIiE. Annars är resultatet den delade variabelnIiE. - Om
Iidentifierar en delad händelse och ingen typargumentlista angavs är resultatet en händelseåtkomst utan associerat måluttryck. - Om
Iidentifierar en konstant och ingen typargumentlista angavs blir resultatet värdet för den konstanten. - Om
Iidentifierar en uppräkningsmedlem och ingen typargumentlista angavs är resultatet värdet för den uppräkningsmedlemmen. - Annars är
E.Ien ogiltig medlemsreferens och ett kompileringsfel inträffar.
- Om
Om
Eklassificeras som en variabel eller ett värde, vars typ ärT, görs medlemssökningen i kontextenT. OmIär namnet på en tillgänglig medlem iTE.Iutvärderas och klassificeras följande:- Om
Iär nyckelordetNew,EärMe,MyBase, ellerMyClass, och inga typargument angavs, är resultatet en metodgrupp som representerar instanskonstruktorerna av typen medEett associerat måluttryck av och ingen typargumentlistaE. Annars uppstår ett kompileringsfel. - Om
Iidentifierar en eller flera metoder, inklusive tilläggsmetoder omTinteObject, är resultatet en metodgrupp med den associerade typargumentlistan och ett associerat måluttryck förE. - Om
Iidentifierar en eller flera egenskaper och inga typargument har angetts är resultatet en egenskapsgrupp med ett associerat måluttryck avE. - Om
Iidentifierar 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 variabelnIi objektet som refereras avE. OmTär en referenstyp blir resultatet variabelnIi objektet som refereras avE. Annars, omTär en värdetyp och uttrycketEklassificeras som en variabel, är resultatet en variabel. Annars är resultatet ett värde. - Om
Iidentifierar en händelse och inga typargument har angetts är resultatet en händelseåtkomst med ett associerat måluttryck avE. - Om
Iidentifierar en konstant och inga typargument angavs är resultatet värdet för den konstanten. - Om
Iidentifierar en uppräkningsmedlem och inga typargument har angetts är resultatet värdet för den uppräkningsmedlemmen. - Om
TärObjectär resultatet ett sent bundet medlemsuppslag klassificerat som en sen bunden åtkomst med den associerade typargumentlistan och ett associerat måluttryck förE.
- Om
Annars är
E.Ien 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
TypeToCollectanger 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
CreateInstanceMethodNameanger vilken metod som ska anropas i gruppklassen för att skapa en ny instans i en standardinstansegenskap.Parametern
DisposeInstanceMethodNameanger vilken metod som ska anropas i gruppklassen för att ta bort en standardinstansegenskap om standardinstansegenskapen tilldelas värdetNothing.Parametern
DefaultInstanceAliasanger vilket uttryckE'som ska ersätta klassnamnet om standardinstanserna är tillgängliga direkt via deras typnamn. Om den här parametern ärNothingeller 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 parameternDefaultInstanceAlias, 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:
- Först kontrolleras varje kapslad typ som innehåller uttrycket, från den innersta och går till den yttersta.
- Sedan kontrolleras varje kapslad namnrymd, från den innersta och går till det yttersta namnområdet.
- Sedan kontrolleras importerna i källfilen.
- 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, ellerSystem.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.IndexOutOfRangeExceptionundantag. Varje uttryck måste vara implicit konvertibelt för att kunna skrivaInteger. 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
Getaccessor 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
ObjectellerSystem.Array, skjuts bearbetningen av indexuttrycket upp till körningstiden och indexeringen är sen bunden. Uttrycket resulterar i en sent bunden egenskapsåtkomst som skrivs somObject. 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.AmbiguousMatchExceptionundantag. Resultatet bearbetas antingen som en egenskapsåtkomst eller som ett anrop och resultatet returneras. Om anropet är av en subrutin blirNothingresultatet .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.MissingMemberExceptionundantag.
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 intePartialeller har en kropp.Både
MochDär funktioner, ellerDär en underrutin.MochDhar samma antal parametrar.Parametertyperna för
Mvar 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 returtypenD.
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
Mhar en bredare konvertering till motsvarande parametertypD.Eller så har returtypen, om någon,
Men begränsad konvertering till returtypenD.
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
Lhar parametrar,Dhar samma antal parametrar. (OmLdet inte finns några parametrar ignoreras parametrarnaDför.)Parametertyperna för
Lvar och en har en konvertering till typen av motsvarande parametertyp ,Doch deras modifierare (dvs.ByRef,ByVal) matchar.Om
Där en funktion har returtypenLen konvertering till returtypenD. (OmDär en underrutin ignoreras returvärdetLfö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
xhärleder namnetx.Ett medlemsåtkomstuttryck
x.yhärleder namnety.Ett ordlisteuppslagsuttryck
x!yhärleder namnety.Ett anrops- eller indexuttryck utan argument
x()härleder namnetx.Ett XML-medlemsåtkomstuttryck
x.<y>,x...<y>,x.@yhärleder namnety.Ett XML-medlemsåtkomstuttryck som är målet för ett medlemsåtkomstuttryck
x.<y>.zhärleder namnetz.Ett XML-medlemsåtkomstuttryck som är målet för ett anrop eller indexuttryck utan argument
x.<y>.z()härleder namnetz.Ett XML-medlemsåtkomstuttryck som är målet för ett anrop eller indexuttryck
x.<y>(0)härleder namnety.
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:
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.
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 ,AndochOrvara ö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,ULongochLong. Om heltalsöverflödeskontrollen är på och summan ligger utanför resultattypens intervall genereras ettSystem.OverflowExceptionundantag. I annat fall rapporteras inte spill och några betydande högordningsbitar av resultatet ignoreras.SingleochDouble. 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 ettSystem.OverflowExceptionundantag. Om resultatvärdet är för litet för att representeras i decimalformatet är resultatet 0.String. De tvåStringoperanderna sammanfogas tillsammans.Date. TypenSystem.DateTimedefinierar överlagrade tilläggsoperatorer. EftersomSystem.DateTimemotsvarar den inbyggdaDatetypen är dessa operatorer också tillgängliga förDatetypen.
Å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,ULongochLong. Om kontroll av heltalsspill är aktiverat och skillnaden ligger utanför resultattypens intervall genereras ettSystem.OverflowExceptionundantag. I annat fall rapporteras inte spill och några betydande högordningsbitar av resultatet ignoreras.SingleochDouble. 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 ettSystem.OverflowExceptionundantag. Om resultatvärdet är för litet för att representeras i decimalformatet är resultatet 0.Date. TypenSystem.DateTimedefinierar överlagrade subtraktionsoperatorer. EftersomSystem.DateTimemotsvarar den inbyggdaDatetypen är dessa operatorer också tillgängliga förDatetypen.
Å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,ULongochLong. Om kontroll av heltalsspill är aktiverat och produkten ligger utanför resultattypens intervall genereras ettSystem.OverflowExceptionundantag. I annat fall rapporteras inte spill och några betydande högordningsbitar av resultatet ignoreras.SingleochDouble. 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 ettSystem.OverflowExceptionundantag. 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:
SingleochDouble. Kvoten beräknas enligt reglerna i IEEE 754-aritmetik.Decimal. Om värdet för rätt operand är noll genereras ettSystem.DivideByZeroExceptionundantag. Om det resulterande värdet är för stort för att representeras i decimalformat genereras ettSystem.OverflowExceptionundantag. 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,IntegerochULongLong. Resultatet avx Mod yär värdet som genereras avx - (x \ y) * y. Omyär noll genereras ettSystem.DivideByZeroExceptionundantag. Modulooperatorn orsakar aldrig ett spill.SingleochDouble. Resten beräknas enligt reglerna i IEEE 754-aritmetik.Decimal. Om värdet för rätt operand är noll genereras ettSystem.DivideByZeroExceptionundantag. Om det resulterande värdet är för stort för att representeras i decimalformat genereras ettSystem.OverflowExceptionundantag. 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.Trueanses vara mindre änFalse, vilket matchar deras numeriska värden.Byte,SByte,UShort,Short,UInteger,Integer,ULongochLong. Operatorerna jämför de numeriska värdena för de två integrerade operanderna.SingleochDouble. 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 -instruktionenOption 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 exklusiv
Orå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. 1Xor0 = 1, 1Xor1 = 0).
När de logiska operatorerna
AndochOrlyfts för typenBoolean?utökas de till att omfatta boolesk logik med tre värden som sådan:Andutvärderas till sant om båda operanderna är sanna; false om någon av operanderna är falsk;Nothingannars.Orutvärderas till sant om någon av operanderna är sanna; false är att båda operanderna är falska;Nothingannars.
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 tillFalseeller returnerar Sant från operatornIsFalsereturnerar uttrycket sin första operande. Annars utvärderas den andra operanden och en logiskAndåtgärd utförs på de två resultaten.Om den första operanden i en
OrElseåtgärd utvärderas tillTrueeller returnerar Sant från operatornIsTruereturnerar uttrycket sin första operande. Annars utvärderas den andra operanden och en logiskOrå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ärBooleanellerBoolean?Thar en bredare konvertering tillBooleanThar en bredare konvertering tillBoolean?Tdefinierar två pseudooperatorerIsTrueochIsFalse.Thar en begränsad konvertering tillBoolean?som inte omfattar en konvertering frånBooleantillBoolean?.Thar en begränsad konvertering tillBoolean.
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
Returnuttryck i instruktionsblocket.I ett asynkront lambda-uttryck är
Task(Of T)returtypen därTär den dominerande typen av uttryck i allaReturnuttryck i instruktionsblocket.I ett lambda-uttryck för iterator är
IEnumerable(Of T)returtypen denTdominerande typen av uttryck i allaYielduttryck 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 ErrorochResume-instruktioner tillåts inte, även omTryinstruktioner 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 avMeinte ä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 matchandeFunctyp.Typen
System.Linq.Expressions.Expression(Of D)kan användas i stället för ombudstypenFunc, förutsatt att detDär en ombudstyp som har samma signatur, inklusive returtyp, som matchningstypFunc.Typen
Trepresenterar 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
Srepresenterar elementtypen för den andra indatasamlingen när det gäller frågeoperatorer som utför kopplingar.Typen
Krepresenterar en nyckeltyp för frågeoperatorer som har en uppsättning intervallvariabler som fungerar som nycklar.Typen
Nrepresenterar 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
Brepresenterar en typ som kan användas i ett booleskt uttryck.Typen
Rrepresenterar elementtypen för resultatsamlingen, om frågeoperatorn skapar en resultatsamling.Rberor på antalet intervallvariabler i omfånget när frågeoperatorn avslutas. Om en enskild intervallvariabel finns i omfånget är detRtypen av intervallvariabel. I exempletDim custNames = From c In Customers Select c.Nameresultatet av frågan blir en samlingstyp med en elementtyp av
String. Om flera intervallvariabler finns i omfånget är detRen anonym typ som innehåller alla intervallvariabler i omfånget somKeyfält. I exemplet:Dim custNames = From c In Customers, o In c.Orders Select Name = c.Name, ProductName = o.ProductNameresultatet av frågan blir en samlingstyp med en elementtyp av en anonym typ med en skrivskyddad egenskap med namnet
NametypStringoch en skrivskyddad egenskap med namnetProductNameav typenString.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
cochonås utan kvalificering iSelectfrågeoperatorn, även om indatasamlingens elementtyp var en anonym typ.Typen
CXrepresenterar en samlingstyp, inte nödvändigtvis indatasamlingstypen, vars elementtyp är någon typX.
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 CTsom kan anropas för att hämta en frågebar samling. Om båda metoderna tillhandahålls
AsQueryableföredras framförAsEnumerable.Den måste ha en metod
Function Cast(Of T)() As CTsom 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>.ValueElementå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").ValueAttributå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.@ageAttributåtkomstmappningar till funktionen:
Function AttributeValue(name As System.Xml.Linq.XName) as StringExemplet ovan motsvarar alltså:
Dim customerAge = customer.AttributeValue("age")Observera. Tilläggsmetoden
AttributeValue(samt den relaterade tilläggsegenskapenValue) 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.XContaineren härledd typ ellerSystem.Collections.Generic.IEnumerable(Of T)en härledd typ, därTärSystem.Xml.Linq.XContainereller en härledd typ.Om en attributåtkomst,
System.Xml.Linq.XElementen härledd typ ellerSystem.Collections.Generic.IEnumerable(Of T)en härledd typ, därTärSystem.Xml.Linq.XElementeller 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:
Cinnehåller en tillgänglig instans eller tilläggsmetod med namnetGetAwaitersom inte har några argument och som returnerar någon typE;Einnehåller en läsbar instans- eller tilläggsegenskap med namnetIsCompletedsom inte tar några argument och har typen Boolesk.Einnehåller en tillgänglig instans eller tilläggsmetod med namnetGetResultsom inte tar några argument.Eimplementerar antingenSystem.Runtime.CompilerServices.INotifyCompletionellerICriticalNotifyCompletion.
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.
Metoden
GetAwaiterför den väntande operanden anropas. Resultatet av det här anropet kallas för den som väntar.Awaiter-egenskapen hämtas
IsCompleted. Om resultatet är sant:- Metoden
GetResultför awaiter anropas. OmGetResultvar en funktion är värdet för await-uttrycket returvärdet för den här funktionen.
- Metoden
Om egenskapen IsCompleted inte är sann:
Antingen
ICriticalNotifyCompletion.UnsafeOnCompletedanropas den som väntar (om inväntarens typEimplementerarICriticalNotifyCompletion) ellerINotifyCompletion.OnCompleted(annars). I båda fallen skickas ett återtagandedelegat som är associerat med den aktuella instansen av async-metoden.Kontrollpunkten för den aktuella asynkrona metodinstansen pausas och kontrollflödet återupptas i den aktuella anroparen (definieras i Avsnitt Async-metoder).
Om återupptagningsdelegaten senare anropas anropas
- återtagandedelegaten återställer
System.Threading.Thread.CurrentThread.ExecutionContextförst till vad det var vid den tidpunktOnCompleteddå anropades, - sedan återupptas kontrollflödet vid kontrollpunkten för asynkron metodinstansen (se Avsnitt Async-metoder),
- där den anropar
GetResultinväntarens metod, som i 2.1 ovan.
- återtagandedelegaten återställer
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.
Visual Basic language spec