Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Výraz je posloupnost operátorů a operandů, které určují výpočet hodnoty nebo který určuje proměnnou nebo konstantu. Tato kapitola definuje syntaxi, pořadí vyhodnocení operandů a operátorů a význam výrazů.
Expression
: SimpleExpression
| TypeExpression
| MemberAccessExpression
| DictionaryAccessExpression
| InvocationExpression
| IndexExpression
| NewExpression
| CastExpression
| OperatorExpression
| ConditionalExpression
| LambdaExpression
| QueryExpression
| XMLLiteralExpression
| XMLMemberAccessExpression
;
Klasifikace výrazů
Každý výraz se klasifikuje jako jeden z následujících výrazů:
Hodnota. Každá hodnota má přidružený typ.
Proměnná. Každá proměnná má přidružený typ, konkrétně deklarovaný typ proměnné.
Jmenný prostor. Výraz s touto klasifikací se může zobrazit pouze na levé straně přístupu člena. V jakémkoli jiném kontextu výraz klasifikovaný jako obor názvů způsobí chybu v době kompilace.
Jeden typ. Výraz s touto klasifikací se může zobrazit pouze na levé straně přístupu člena. V jakémkoli jiném kontextu výraz klasifikovaný jako typ způsobí chybu v době kompilace.
Skupina metod, což je sada metod přetížených ve stejném názvu. Skupina metod může mít přidružený cílový výraz a seznam argumentů přidruženého typu.
Ukazatel metody, který představuje umístění metody. Ukazatel metody může mít přidružený cílový výraz a seznam argumentů přidruženého typu.
Metoda lambda, což je anonymní metoda.
Skupina vlastností, což je sada vlastností přetížených ve stejném názvu. Skupina vlastností může mít přidružený cílový výraz.
Přístup k vlastnosti. Každý přístup k vlastnostem má přidružený typ, konkrétně typ vlastnosti. Přístup k vlastnosti může mít přidružený cílový výraz.
Opožděný přístup, který představuje metodu nebo přístup k vlastnostem odložený do doby běhu. Pozdní přístup může mít přidružený cílový výraz a seznam argumentů přidruženého typu. Typ pozdního přístupu je vždy
Object.Přístup k události. Každý přístup k události má přidružený typ, konkrétně typ události. Přístup k události může mít přidružený cílový výraz. Přístup k události se může zobrazit jako první argument příkazu
RaiseEvent,AddHandleraRemoveHandlerpříkazy. V jakémkoli jiném kontextu výraz klasifikovaný jako přístup k události způsobí chybu v době kompilace.Literál pole, který představuje počáteční hodnoty pole, jehož typ ještě nebyl určen.
Prázdnota. K tomu dochází v případě, že výraz je vyvoláním podprogramu nebo výraz operátoru await bez výsledku. Výraz klasifikovaný jako void je platný pouze v kontextu vyvolání příkazu nebo příkazu await.
Výchozí hodnota. Tuto klasifikaci vytvoří pouze literál
Nothing.
Konečný výsledek výrazu je obvykle hodnota nebo proměnná, přičemž ostatní kategorie výrazů fungují jako přechodné hodnoty, které jsou povoleny pouze v určitých kontextech.
Všimněte si, že výrazy, jejichž typ je parametr typu, lze použít v příkazech a výrazech, které vyžadují typ výrazu, aby měly určité vlastnosti (například odkazový typ, typ hodnoty, odvozený z některého typu atd.), pokud omezení uložená parametrem typu splňují tyto vlastnosti.
Změna klasifikace výrazů
Obvykle platí, že když se výraz používá v kontextu, který vyžaduje klasifikaci odlišnou od výrazu, dojde k chybě v době kompilace – například při pokusu o přiřazení hodnoty literálu. V mnoha případech je však možné změnit klasifikaci výrazu prostřednictvím procesu přetřídění.
Pokud je změna klasifikace úspěšná, bude změna klasifikace považována za rozšíření nebo zúžení. Pokud není uvedeno jinak, všechny přetříděné klasifikace v tomto seznamu se rozšiřují.
Lze přetřídět následující typy výrazů:
Proměnnou lze přetřídět jako hodnotu. Hodnota uložená v proměnné se načte.
Skupinu metod lze přetřídět jako hodnotu. Výraz skupiny metod je interpretován jako vyvolání výrazu s přidruženým cílovým výrazem a seznamem parametrů typu a prázdnými závorky (to znamená,
fže je interpretován jakof()af(Of Integer)interpretován jakof(Of Integer)()). Toto přetřídění může vést k dalšímu přetřídění výrazu jako void.Ukazatel metody lze přetřídět jako hodnotu. K této přetříděné klasifikaci může dojít pouze v kontextu převodu, ve kterém je cílový typ známý. Výraz ukazatele metody je interpretován jako argument delegované instance výrazu odpovídajícího typu se seznamem argumentů přidruženého typu. Například:
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 ModuleMetodu lambda lze přetřídět jako hodnotu. Pokud dojde k přetřídění v kontextu převodu, ve kterém je cílový typ známý, může dojít k jedné ze dvou přetříděných tříd:
Pokud je cílovým typem typu delegát, metoda lambda je interpretována jako argument výrazu delegate-construction příslušného typu.
Pokud je
System.Linq.Expressions.Expression(Of T)cílový typ aTje typem delegáta, pak je metoda lambda interpretována, jako by byla použita ve výrazu delegate-construction proTa pak převedena na strom výrazu.
Asynchronní metoda nebo metoda lambda iterátoru lze interpretovat pouze jako argument výrazu delegate-construction, pokud delegát nemá žádné parametry ByRef.
Pokud převod z některého z typů parametrů delegáta na odpovídající typy parametrů lambda je zužující převod, pak je změna klasifikace považována za zúžení; v opačném případě se rozšiřuje.
Poznámka. Přesný překlad mezi metodami lambda a stromy výrazů nemusí být mezi verzemi kompilátoru opraven a přesahuje rozsah této specifikace. U jazyka Microsoft Visual Basic 11.0 mohou být všechny výrazy lambda převedeny na stromy výrazů, které podléhají následujícím omezením: (1) 1. Pouze jednořádkové výrazy lambda bez parametrů ByRef mohou být převedeny na stromy výrazů. Z jednořádkových
Sublambda je možné převést pouze vyvolání příkazů na stromy výrazů. (2) Anonymní výrazy typu nelze převést na stromy výrazů, pokud se k inicializaci následného inicializátoru pole používá dřívější inicializátor pole, např.New With {.a=1, .b=.a}(3) Výrazy inicializátoru objektů nelze převést na stromy výrazů, pokud je člen aktuálního objektu inicializován v jednom z inicializátorů polí, napříkladNew C1 With {.a=1, .b=.Method1()}. (4) Výrazy pro vytváření vícerozměrných polí lze převést pouze na stromy výrazů, pokud deklarují svůj typ prvku explicitně. (5) Výrazy s pozdní vazbou nelze převést na stromy výrazů. (6) Při předání proměnné nebo pole ByRef do vyvolání výrazu, ale nemá přesně stejný typ jako ByRef parametr, nebo když je vlastnost předána ByRef, normální sémantika VB je předána kopie argumentu ByRef a jeho konečná hodnota se pak zkopíruje zpět do proměnné nebo pole nebo vlastnosti. Ve stromech výrazů nedojde ke zpětnému kopírování. (7) Všechna tato omezení platí i pro vnořené výrazy lambda.Pokud cílový typ není znám, metoda lambda je interpretována jako argument delegovaného výrazu instance anonymního typu delegáta se stejným podpisem metody lambda. Pokud se používá striktní sémantika a typ některého z parametrů je vynechán, dojde k chybě v době kompilace;
Objectv opačném případě se nahradí chybějícím typem parametru. Například: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 ModuleSkupinu vlastností lze přetřídět jako přístup k vlastnosti. Výraz skupiny vlastností je interpretován jako výraz indexu s prázdnými závorky (to znamená,
fže je interpretován jakof()).Přístup k vlastnosti lze přetřídět jako hodnotu. Výraz přístupu k vlastnosti je interpretován jako vyvolání výrazu přístupového
Getobjektu vlastnosti. Pokud vlastnost nemá žádný getter, dojde k chybě kompilace.Přístup s pozdní vazbou lze přetřídět jako metodu pozdní vazby nebo přístup k vlastnosti s pozdní vazbou. V situaci, kdy je možné přetřídět přístup s pozdní vazbou jak jako přístup k metodě, tak jako přístup k vlastnosti, je upřednostňované přetřídění přístupu k vlastnosti.
Pozdní přístup lze přetřídět jako hodnotu.
Literál pole lze přetřídět jako hodnotu. Typ hodnoty je určen takto:
Pokud dojde k přetřídění v kontextu převodu, ve kterém je cílový typ známý a cílový typ je typ pole, pak se literál pole přetřídí jako hodnota typu T(). Pokud je
System.Collections.Generic.IList(Of T)cílový typ , ,IReadOnlyList(Of T),ICollection(Of T),IReadOnlyCollection(Of T)neboIEnumerable(Of T), a literál pole má jednu úroveň vnoření, pak je literál pole přetříděn jako hodnota typuT().Jinak je literál pole přetříděn na hodnotu, jejíž typ je matice pořadí rovna úrovni vnoření, je použita s typem prvku určeným dominantním typem prvků v inicializátoru; pokud nelze určit žádný dominantní typ,
Objectpoužije se. Například:' 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()
Poznámka. Mezi verzí 9.0 a verzí 10.0 jazyka se mírně mění chování. Před verzí 10.0 nebyly inicializátory elementů pole ovlivněny odvození místního typu proměnné a nyní to dělají. Bylo by tedy
Dim a() = { 1, 2, 3 }odvozenoObject()jako typajazyka verze 9.0 aInteger()ve verzi 10.0.Přetřídění pak reinterpretuje literál pole jako výraz pro vytvoření pole. Příklady:
Dim x As Double = { 1, 2, 3, 4 } Dim y = { "a", "b" }jsou ekvivalentní:
Dim x As Double = New Double() { 1, 2, 3, 4 } Dim y = New String() { "a", "b" }Přetřídění je považováno za zúžení, pokud jakýkoli převod z výrazu prvku na typ prvku pole je zúžen; v opačném případě se soudí jako rozšiřující.
Výchozí hodnotu
Nothinglze přetřídět jako hodnotu. V kontextu, kde je známý cílový typ, je výsledkem výchozí hodnota cílového typu. V kontextu, kde cílový typ není znám, je výsledkem hodnota null typuObject.
Výraz oboru názvů, výraz typu, výraz pro přístup k událostem nebo výraz void nelze přetřídět. Více přetříděných tříd lze provést současně. Například:
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
V tomto případě je výraz P skupiny vlastností nejprve přetříděn ze skupiny vlastností na přístup k vlastnosti a potom přetříděn z přístupu k vlastnosti přístup k hodnotě. K dosažení platné klasifikace v kontextu se provádí nejmenší počet přetříděných klasifikací.
Konstantní výrazy
Konstantní výraz je výraz, jehož hodnotu lze plně vyhodnotit v době kompilace.
ConstantExpression
: Expression
;
Typ konstantního výrazu může být Byte, , SByte, UShort, Short, UIntegerInteger, , ULong, LongDecimalSingleCharDateBooleanDouble, , String, nebo Objectjakýkoli typ výčtu. Následující konstrukce jsou povoleny ve výrazech konstant:
Literály (včetně
Nothing).Odkazy na členy konstantního typu nebo místní hodnoty konstant.
Odkazy na členy typů výčtu.
Závorky podvýrazy
Převod výrazů za předpokladu, že cílový typ je jedním z výše uvedených typů. Převody do a z
Stringtohoto pravidla jsou výjimkou a jsou povoleny pouze u hodnot null, protožeStringpřevody se vždy provádějí v aktuální jazykové verzi spouštěcího prostředí za běhu. Všimněte si, že výrazy konstantního převodu mohou používat pouze vnitřní převody.Operátory
+aNot-unární operátory za předpokladu, že operand a výsledek jsou typu uvedené výše.Operátory
+, ,-,*,^,\<>And&Or>>Xor<<AndAlsoOrElse/Mod<>=<=, a=>binární operátory, za předpokladu, že každý operand a výsledek je typu uvedený výše.Podmíněný operátor If, za předpokladu, že každý operand a výsledek je typu uvedený výše.
Následující funkce za běhu:
Microsoft.VisualBasic.Strings.ChrW;Microsoft.VisualBasic.Strings.Chrpokud je konstantní hodnota mezi 0 a 128;Microsoft.VisualBasic.Strings.AscWpokud konstantní řetězec není prázdný;Microsoft.VisualBasic.Strings.Ascpokud konstantní řetězec není prázdný.
Následující konstrukce nejsou povoleny ve výrazech konstant:
- Implicitní vazba prostřednictvím
Withkontextu
Konstantní výrazy celočíselného typu (ULong, Long, , UShortIntegerUInteger, Short, SBytenebo Byte) lze implicitně převést na užší celočíselný typ a konstantní výrazy typu Double mohou být implicitně převedeny na Single, za předpokladu, že hodnota konstantního výrazu je v rozsahu cílového typu. Tyto zužující převody jsou povoleny bez ohledu na to, zda se používají permisivní nebo striktní sémantika.
výrazy Late-Bound
Pokud je cíl výrazu přístupu člena nebo výraz indexu typu Object, může být zpracování výrazu odloženo do doby běhu. Odložení zpracování tímto způsobem se označuje jako opožděná vazba. Pozdní vazba umožňuje Object použití proměnných bez typů , kde je veškeré rozlišení členů založeno na skutečném typu doby běhu hodnoty v proměnné. Pokud jsou přísné sémantika určena prostředím kompilace nebo Option Strictpozdní vazbou způsobí chybu v době kompilace. Neveřejní členové se ignorují při provádění pozdní vazby, včetně pro účely řešení přetížení. Všimněte si, že na rozdíl od případu s časnou vazbou způsobí vyvolání Shared nebo přístupu k členu opožděné vazby, aby se cíl vyvolání vyhodnocoval za běhu. Pokud je výraz vyvoláním výrazu pro člen definovaný System.Objectdne , pozdní vazby se neprovedou.
Obecně platí, že pozdní přístupy jsou vyřešeny za běhu vyhledáním identifikátoru skutečného typu běhu výrazu. Pokud vyhledávání členů s pozdní vazbou v době běhu selže, vyvolá System.MissingMemberException se výjimka. Vzhledem k tomu, že vyhledávání členů s pozdní vazbou se provádí výhradně mimo typ běhu přidruženého cílového výrazu, typ běhu objektu není nikdy rozhraním. Proto není možné získat přístup k členům rozhraní ve výrazu přístupu ke členům s pozdní vazbou.
Argumenty přístupu k pozdátným členům se vyhodnocují v pořadí, v jakém se zobrazují ve výrazu přístupu člena: nikoli v pořadí, ve kterém jsou parametry deklarovány v členu s pozdní vazbou. Následující příklad ukazuje tento rozdíl:
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
Tento kód zobrazí:
Early-bound: xy
Late-bound: yx
Vzhledem k tomu, že překlad přetížení s pozdní vazbou se provádí u typu běhu argumentů, je možné, že výraz může vytvářet různé výsledky na základě toho, zda je vyhodnocen v době kompilace nebo v době běhu. Následující příklad ukazuje tento rozdíl:
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
Tento kód zobrazí:
F(Base)
F(Derived)
Jednoduché výrazy
Jednoduché výrazy jsou literály, závorky, výrazy instancí nebo jednoduché výrazy názvů.
SimpleExpression
: LiteralExpression
| ParenthesizedExpression
| InstanceExpression
| SimpleNameExpression
| AddressOfExpression
;
Literální výrazy
Literální výrazy se vyhodnotí jako hodnota reprezentovaná literálem. Literálový výraz je klasifikován jako hodnota, s výjimkou literálu Nothing, který je klasifikován jako výchozí hodnota.
LiteralExpression
: Literal
;
Výrazy s závorkovanou závorky
Výraz s závorkou se skládá z výrazu uzavřeného v závorkách. Výraz s závorkou je klasifikován jako hodnota a uzavřený výraz musí být klasifikován jako hodnota. Výraz v závorkách se vyhodnotí jako hodnota výrazu v závorkách.
ParenthesizedExpression
: OpenParenthesis Expression CloseParenthesis
;
Výrazy instance
Výraz instance je klíčové slovo Me. Lze jej použít pouze v těle nesdílené metody, konstruktoru nebo přístupového objektu vlastnosti. Klasifikuje se jako hodnota. Klíčové slovo Me představuje instanci typu obsahujícího metodu nebo přístupové objekty vlastností, které se spouští. Pokud konstruktor explicitně vyvolá jiný konstruktor ( Section Constructors), Me nelze použít, dokud tento konstruktor volání, protože instance ještě nebyla vytvořena.
InstanceExpression
: 'Me'
;
Výrazy s jednoduchým názvem
Jednoduchý výraz názvu se skládá z jednoho identifikátoru následovaného seznamem argumentů volitelného typu.
SimpleNameExpression
: Identifier ( OpenParenthesis 'Of' TypeArgumentList CloseParenthesis )?
;
Název se přeloží a klasifikuje podle následujících "jednoduchých pravidel překladu ip adres":
Počínaje okamžitě uzavřeným blokem a pokračováním s každým uzavřeným vnějším blokem (pokud existuje), pokud identifikátor odpovídá názvu místní proměnné, statické proměnné, konstantní místní, parametru typu metody nebo parametru, pak identifikátor odkazuje na odpovídající entitu.
Pokud identifikátor odpovídá místní proměnné, statické proměnné nebo konstantě a byl zadán seznam argumentů typu, dojde k chybě v době kompilace. Pokud identifikátor odpovídá parametru typu metody a byl zadán seznam argumentů typu, nedojde k žádné shodě a řešení bude pokračovat. Pokud identifikátor odpovídá místní proměnné, odpovídá místní proměnné implicitní funkce nebo
Getpřístupová proměnná, která vrací místní proměnnou a výraz je součástí vyvolání výrazu, příkazu vyvolání neboAddressOfvýrazu, nedojde k žádné shodě a pokračuje překlad.Výraz se klasifikuje jako proměnná, pokud se jedná o místní proměnnou, statickou proměnnou nebo parametr. Výraz je klasifikovaný jako typ, pokud se jedná o parametr typu metody. Výraz je klasifikován jako hodnota, pokud se jedná o konstantní místní.
Pro každý vnořený typ obsahující výraz, počínaje nejvíce vnitřní a přechod na vnější, pokud vyhledávání identifikátoru v typu vytvoří shodu s přístupným členem:
- Pokud je odpovídající člen typu parametr typu, výsledek se klasifikuje jako typ a je odpovídající parametr typu. Pokud byl zadán seznam argumentů typu, nedojde k žádné shodě a řešení bude pokračovat.
- V opačném případě, pokud je typ bezprostředně uzavřený a vyhledávání identifikuje nesdílený typ člen, je výsledek stejný jako přístup člena formuláře
Me.E(Of A), kdeEje identifikátor aAje seznam argumentů typu, pokud existuje. - V opačném případě je výsledek úplně stejný jako přístup člena formuláře
T.E(Of A), kdeTje typ obsahující odpovídající člen,Eje identifikátor aAje seznam argumentů typu, pokud existuje. V tomto případě se jedná o chybu, která identifikátor odkazuje na nesdílený člen.
Pro každý vnořený obor názvů, počínaje nejvíce vnitřní a přechod na vnější obor názvů, postupujte takto:
- Pokud obor názvů obsahuje přístupný typ s daným názvem a má stejný počet parametrů typu, jako byl zadán v seznamu argumentů typu, pak identifikátor odkazuje na tento typ a je klasifikován jako typ.
- Jinak pokud nebyl zadán seznam argumentů typu a obor názvů obsahuje člena oboru názvů s daným názvem, identifikátor odkazuje na tento obor názvů a je klasifikován jako obor názvů.
- V opačném případě pokud obor názvů obsahuje jeden nebo více přístupných standardních modulů a vyhledávání názvu člena identifikátoru vytvoří přístupnou shodu v přesně jednom standardním modulu, pak je výsledek úplně stejný jako přístup člena formuláře
M.E(Of A), kdeMje standardní modul obsahující odpovídající člen,Eje identifikátor aAje seznam argumentů typu, pokud existuje. Pokud identifikátor odpovídá členům přístupného typu ve více než jednom standardním modulu, dojde k chybě v době kompilace.
Pokud má zdrojový soubor jeden nebo více aliasů importu a identifikátor odpovídá názvu jednoho z nich, identifikátor odkazuje na tento obor názvů nebo typ. Pokud je zadán seznam argumentů typu, dojde k chybě v době kompilace.
Pokud zdrojový soubor obsahující odkaz na název obsahuje jeden nebo více importů:
- Pokud se identifikátor shoduje s přesně jedním importem názvu přístupného typu se stejným počtem parametrů typu, jako byl zadán v seznamu argumentů typu, pokud existuje nebo člen typu, pak identifikátor odkazuje na tento typ nebo člen typu. Pokud identifikátor odpovídá více než jednomu importu názvu přístupného typu se stejným počtem parametrů typu, jaké byl zadán v seznamu argumentů typu, pokud existuje nebo je členem přístupného typu, dojde k chybě v době kompilace.
- Jinak pokud nebyl zadán žádný seznam argumentů typu a identifikátor odpovídá přesně v jednom importu názvu oboru názvů s dostupnými typy, identifikátor odkazuje na tento obor názvů. Pokud nebyl zadán žádný seznam argumentů typu a identifikátor odpovídá více než jednomu importu názvu oboru názvů s dostupnými typy, dojde k chybě v době kompilace.
- V opačném případě, pokud importy obsahují jeden nebo více přístupných standardních modulů a vyhledávání názvu člena identifikátoru vytvoří přístupnou shodu v přesně jednom standardním modulu, pak je výsledek úplně stejný jako přístup člena formuláře
M.E(Of A), kdeMje standardní modul obsahující odpovídající člen,Eje identifikátor aAje seznam argumentů typu, pokud existuje. Pokud identifikátor odpovídá členům přístupného typu ve více než jednom standardním modulu, dojde k chybě v době kompilace.
Pokud prostředí kompilace definuje jeden nebo více aliasů importu a identifikátor odpovídá názvu jednoho z nich, identifikátor odkazuje na tento obor názvů nebo typ. Pokud je zadán seznam argumentů typu, dojde k chybě v době kompilace.
Pokud prostředí kompilace definuje jeden nebo více importů:
- Pokud se identifikátor shoduje s přesně jedním importem názvu přístupného typu se stejným počtem parametrů typu, jako byl zadán v seznamu argumentů typu, pokud existuje nebo člen typu, pak identifikátor odkazuje na tento typ nebo člen typu. Pokud identifikátor odpovídá více než jednomu importu názvu přístupného typu se stejným počtem parametrů typu, jako byl zadán v seznamu argumentů typu, pokud existuje nebo člen typu, dojde k chybě v době kompilace.
- Jinak pokud nebyl zadán žádný seznam argumentů typu a identifikátor odpovídá přesně v jednom importu názvu oboru názvů s dostupnými typy, identifikátor odkazuje na tento obor názvů. Pokud nebyl zadán žádný seznam argumentů typu a identifikátor odpovídá více než jednomu importu názvu oboru názvů s dostupnými typy, dojde k chybě v době kompilace.
- V opačném případě, pokud importy obsahují jeden nebo více přístupných standardních modulů a vyhledávání názvu člena identifikátoru vytvoří přístupnou shodu v přesně jednom standardním modulu, pak je výsledek úplně stejný jako přístup člena formuláře
M.E(Of A), kdeMje standardní modul obsahující odpovídající člen,Eje identifikátor aAje seznam argumentů typu, pokud existuje. Pokud identifikátor odpovídá členům přístupného typu ve více než jednom standardním modulu, dojde k chybě v době kompilace.
V opačném případě je název zadaný identifikátorem nedefinovaný.
Jednoduchý výraz názvu, který není definován, je chyba v době kompilace.
Za normálních okolností může název nastat pouze jednou v určitém oboru názvů. Vzhledem k tomu, že obory názvů lze deklarovat napříč více sestaveními .NET, je možné mít situaci, kdy dvě sestavení definují typ se stejným plně kvalifikovaným názvem. V takovém případě je typ deklarovaný v aktuální sadě zdrojových souborů upřednostňovaný před typem deklarovaným v externím sestavení .NET. V opačném případě je název nejednoznačný a neexistuje způsob, jak nejednoznačit název.
Výrazy AddressOf
Výraz AddressOf se používá k vytvoření ukazatele metody. Výraz se skládá z klíčového slova a výrazu AddressOf , který musí být klasifikován jako skupina metod nebo opožděný přístup. Skupina metod nemůže odkazovat na konstruktory.
Výsledek se klasifikuje jako ukazatel metody se stejným přidruženým cílovým výrazem a seznamem argumentů typu (pokud existuje) jako skupina metod.
AddressOfExpression
: 'AddressOf' Expression
;
Výrazy typu
Výraz typu je GetType výraz, TypeOf...Is výraz, Is výraz nebo GetXmlNamespace výraz.
TypeExpression
: GetTypeExpression
| TypeOfIsExpression
| IsExpression
| GetXmlNamespaceExpression
;
Výrazy GetType
Výraz GetType se skládá z klíčového slova GetType a názvu typu.
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*
;
Výraz GetType je klasifikován jako hodnota a jeho hodnota je reflexe (System.Type) třída, která představuje jeho GetTypeTypeName. Pokud GetTypeTypeName je parametr typu, výraz vrátí System.Type objekt, který odpovídá argumentu typu zadaný pro parametr typu za běhu.
GetTypeTypeName je speciální dvěma způsoby:
Je povoleno ,
System.Voidjediné místo v jazyce, kde tento název typu může být odkazován.Může to být vytvořený obecný typ s vynechanými argumenty typu. To umožňuje
GetTypevýrazu vrátitSystem.Typeobjekt, který odpovídá samotnému obecnému typu.
Následující příklad ukazuje GetType výraz:
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
Výsledný výstup je:
Int32
Int32
String
Double[]
TypeOf... Výrazy Is
Výraz TypeOf...Is slouží ke kontrole, zda je typ běhu hodnoty kompatibilní s daným typem. První operand musí být klasifikovaný jako hodnota, nemůže být přetříděnou metodou lambda a musí být typu odkazu nebo typu parametru unconstrained type. Druhý operand musí být název typu. Výsledek výrazu je klasifikován jako hodnota a je Boolean hodnota. Výraz se vyhodnotí tak, že True pokud má typ operandu za běhu identitu, výchozí hodnotu, odkaz, pole, typ hodnoty nebo převod parametru typu na typ, False jinak. K chybě v době kompilace dochází v případě, že mezi typem výrazu a konkrétním typem neexistuje žádný převod.
TypeOfIsExpression
: 'TypeOf' Expression 'Is' LineTerminator? TypeName
;
Výrazy Is
Výraz Is slouží IsNot k porovnání rovnosti odkazů.
IsExpression
: Expression 'Is' LineTerminator? Expression
| Expression 'IsNot' LineTerminator? Expression
;
Každý výraz musí být klasifikovaný jako hodnota a typ každého výrazu musí být odkazový typ, typ parametru nekontrénovaného typu nebo typ hodnoty s možnou hodnotou null. Pokud je typ jednoho výrazu nekontrénovaný typ parametru nebo typ hodnoty null, druhý výraz však musí být literál Nothing.
Výsledek je klasifikován jako hodnota a je zadán jako Boolean. Operace Is se vyhodnotí tak, že True obě hodnoty odkazují na stejnou instanci nebo obě hodnoty jsou Nothing, nebo False jinak. Operace IsNot se vyhodnotí tak, že False obě hodnoty odkazují na stejnou instanci nebo obě hodnoty jsou Nothing, nebo True jinak.
Výrazy GetXmlNamespace
Výraz GetXmlNamespace se skládá z klíčového slova GetXmlNamespace a názvu oboru názvů XML deklarovaného zdrojovým souborem nebo prostředím kompilace.
GetXmlNamespaceExpression
: 'GetXmlNamespace' OpenParenthesis XMLNamespaceName? CloseParenthesis
;
Výraz GetXmlNamespace je klasifikován jako hodnota a jeho hodnota je instance System.Xml.Linq.XNamespace , která představuje XMLNamespaceNameName. Pokud tento typ není k dispozici, dojde k chybě v době kompilace.
Například:
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
Všechno mezi závorky je považováno za součást názvu oboru názvů, takže pravidla XML týkající se věcí, jako jsou prázdné znaky, platí. Například:
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
Výraz oboru názvů XML lze také vynechat, v takovém případě výraz vrátí objekt, který představuje výchozí obor názvů XML.
Výrazy přístupu členů
Výraz přístupu člena slouží k přístupu k členu entity.
MemberAccessExpression
: MemberAccessBase? Period IdentifierOrKeyword
( OpenParenthesis 'Of' TypeArgumentList CloseParenthesis )?
;
MemberAccessBase
: Expression
| NonArrayTypeName
| 'Global'
| 'MyClass'
| 'MyBase'
;
Přístup člena formuláře E.I(Of A), kde E je výraz, název jiného typu než pole, klíčové slovo Globalnebo vynechaný a I je identifikátor se seznamem Avolitelných argumentů typu , je vyhodnocen a klasifikován takto:
Pokud
Eje vynechán, výraz z bezprostředně obsahujícíhoWithpříkazu se nahradíEa provede se přístup člena. Pokud neexistuje žádný příkaz obsahujícíWith, dojde k chybě v době kompilace.Pokud
Eje klasifikovaný jako obor názvů neboEje klíčovým slovemGlobal, provede se vyhledávání členů v kontextu zadaného oboru názvů. PokudIje název přístupného člena tohoto oboru názvů se stejným počtem parametrů typu, jako byl zadán v seznamu argumentů typu, pokud existuje, výsledek je tento člen. Výsledek se klasifikuje jako obor názvů nebo typ v závislosti na členu. V opačném případě dojde k chybě kompilace.Pokud
Eje typ nebo výraz klasifikovaný jako typ, provede se vyhledávání členů v kontextu zadaného typu. PokudIje název přístupného členaE, pakE.Ise vyhodnotí a klasifikuje takto:- Pokud
Ije klíčové slovoNewaEnení výčtem, dojde k chybě v době kompilace. - Pokud
Iidentifikuje typ se stejným počtem parametrů typu, jako byl zadán v seznamu argumentů typu, pokud existuje, výsledek je tento typ. - Pokud
Iidentifikuje jednu nebo více metod, je výsledkem skupina metod se seznamem argumentů přidružených typů a žádný přidružený cílový výraz. - Pokud
Iidentifikuje jednu nebo více vlastností a nebyl zadán žádný seznam argumentů typu, je výsledkem skupina vlastností bez přidruženého cílového výrazu. - Pokud
Iidentifikuje sdílenou proměnnou a nebyl zadán žádný seznam argumentů typu, je výsledkem proměnná nebo hodnota. Pokud je proměnná jen pro čtení a odkaz se vyskytuje mimo sdílený konstruktor typu, ve kterém je proměnná deklarována, pak je výsledkem hodnota sdílené proměnnéIvE. V opačném případě je výsledkem sdílená proměnnáIvEsouboru . - Pokud
Iidentifikuje sdílenou událost a nebyl zadán žádný seznam argumentů typu, výsledkem je přístup k události bez přidruženého cílového výrazu. - Pokud
Iidentifikuje konstantu a nebyl zadán žádný seznam argumentů typu, je výsledkem hodnota této konstanty. - Pokud
Iidentifikuje člen výčtu a nebyl zadán žádný seznam argumentů typu, je výsledkem hodnota tohoto člena výčtu. - V opačném případě je
E.Ineplatným odkazem na člena a dojde k chybě v době kompilace.
- Pokud
Je-li
Eklasifikována jako proměnná nebo hodnota, typ, který jeT, pak se členské vyhledávání provádí v kontextuT. PokudIje název přístupného členaT, pakE.Ise vyhodnotí a klasifikuje takto:- Pokud
Ije klíčové slovoNew, jeMe,MyBaseEneboMyClass, a nebyly zadány žádné argumenty typu, pak výsledek je skupina metod představující konstruktory instance typuEs přidruženým cílovým výrazemEa žádný seznam argumentů typu. V opačném případě dojde k chybě kompilace. - Pokud
Iidentifikuje jednu nebo více metod, včetně rozšiřujících metod, pokudTneníObject, je výsledkem skupina metod se seznamem argumentů přidruženého typu a přidruženým cílovým výrazemE. - Pokud
Iidentifikuje jednu nebo více vlastností a nebyly zadány žádné argumenty typu, je výsledkem skupina vlastností s přidruženým cílovým výrazemE. - Pokud
Iidentifikuje sdílenou proměnnou nebo proměnnou instance a nebyly zadány žádné argumenty typu, je výsledkem proměnná nebo hodnota. Pokud je proměnná jen pro čtení a odkaz se vyskytuje mimo konstruktor třídy, ve které je proměnná deklarována vhodnou pro druh proměnné (sdílené nebo instance), je výsledkem hodnota proměnnéIv objektu, na kterýEodkazuje . PokudTje typ odkazu, je výsledkem proměnnáIv objektu, na kterýEodkazuje . V opačném případě je-liTtyp hodnoty a výrazEje klasifikován jako proměnná, výsledek je proměnná, jinak je výsledkem hodnota. - Pokud
Iidentifikuje událost a nebyly zadány žádné argumenty typu, výsledkem je přístup k události s přidruženým cílovým výrazemE. - Pokud
Iidentifikuje konstantu a nebyly zadány žádné argumenty typu, je výsledkem hodnota této konstanty. - Pokud
Iidentifikuje člen výčtu a nebyly zadány žádné argumenty typu, je výsledkem hodnota tohoto člena výčtu. - Pokud
TjeObject, pak je výsledkem opožděný člen vyhledávání klasifikovaný jako opožděný přístup se seznamem argumentů přidruženého typu a přidruženým cílovým výrazemE.
- Pokud
V opačném případě je
E.Ineplatným odkazem na člena a dojde k chybě v době kompilace.
Přístup člena formuláře MyClass.I(Of A) je ekvivalentní Me.I(Of A), ale všichni členové, kteří k němu mají přístup, jsou považováni za nepřepsatelné. Přístup ke členu tedy nebude ovlivněn typem běhu hodnoty, ke které se člen přistupuje.
Přístup člena formuláře MyBase.I(Of A) je ekvivalentní CType(Me, T).I(Of A) tomu, kde T je přímým základním typem typu obsahujícího výraz přístupu člena. Všechna vyvolání metody jsou považována za metodu, která je vyvolána, není přepisovatelná. Tato forma přístupu člena se také nazývá základní přístup.
Následující příklad ukazuje, jak Mea MyBaseMyClass souvisí:
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
Tento kód se vytiskne:
MoreDerived.F
Derived.F
Derived.F
Když výraz přístupu člena začíná klíčovým slovem Global, představuje klíčové slovo vnější nepojmenovaný obor názvů, což je užitečné v situacích, kdy deklarace stínuje uzavřený obor názvů. Klíčové Global slovo umožňuje "escaping" do vnějšího oboru názvů v této situaci. Například:
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
V předchozím příkladu je první volání metody neplatné, protože identifikátor System je vázán na třídu System, nikoli obor názvů System. Jediným způsobem, jak získat přístup k System oboru názvů, je použít Global k úniku do vnějšího oboru názvů.
Pokud je člen, ke který se přistupuje, sdílen, je jakýkoli výraz na levé straně období nadbytečný a nevyhodnocuje se, pokud není přístup člena proveden pozdě vázaný. Představte si například následující kód:
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
Vytiskne The value of F is: 10 se, protože funkce ReturnC nemusí být volána, aby poskytla instanci C pro přístup ke sdílenému členu F.
Identické názvy typů a členů
Není neobvyklé pojmenovat členy, kteří používají stejný název jako jejich typ. V takovém případě však může dojít k nevhodnému skrývání názvů:
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
V předchozím příkladu je jednoduchý název Color v DefaultColor vazbách na vlastnost instance namísto typu. Vzhledem k tomu, že na člena instance nelze odkazovat ve sdíleném členu, obvykle by to byla chyba.
Speciální pravidlo však umožňuje přístup k typu v tomto případě. Pokud je základním výrazem výrazu přístupu člena jednoduchý název a vytvoří vazbu na konstantu, pole, vlastnost, místní proměnnou nebo parametr, jehož typ má stejný název, může základní výraz odkazovat buď na člena, nebo typ. To nemůže mít za následek nejednoznačnost, protože členové, ke kterým je možné přistupovat z některé z nich, jsou stejné.
Výchozí instance
V některých situacích mají třídy odvozené od společné základní třídy obvykle nebo vždy pouze jednu instanci. Například většina oken zobrazených v uživatelském rozhraní má vždy jenom jednu instanci, která se zobrazuje na obrazovce kdykoli. Pro zjednodušení práce s těmito typy tříd může Visual Basic automaticky generovat výchozí instance tříd, které poskytují jednu, snadno odkazovanou instanci pro každou třídu.
Výchozí instance se vždy vytvářejí pro řadu typů, nikoli pro jeden konkrétní typ. Takže místo vytvoření výchozí instance pro třídu Form1, která je odvozena z formuláře, výchozí instance jsou vytvořeny pro všechny třídy odvozené z formuláře. To znamená, že každá jednotlivá třída odvozená ze základní třídy nemusí být speciálně označena tak, aby měla výchozí instanci.
Výchozí instance třídy je reprezentována kompilátorem generovaná vlastnost, která vrací výchozí instanci této třídy. Vlastnost vygenerovaná jako člen třídy označovaná jako třída skupiny , která spravuje přidělování a zničení výchozích instancí pro všechny třídy odvozené z konkrétní základní třídy. Například všechny výchozí vlastnosti instance třídy odvozené z Form mohou být shromážděny MyForms ve třídě. Pokud je instance třídy skupiny vrácena výrazem My.Forms, pak následující kód přistupuje k výchozím instancím odvozených tříd Form1 a 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
Výchozí instance nebudou vytvořeny, dokud se na ně neodkazuje první odkaz; Načtení vlastnosti představující výchozí instanci způsobí vytvoření výchozí instance, pokud ještě nebyla vytvořena nebo byla nastavena na Nothing. Chcete-li povolit testování existence výchozí instance, pokud je výchozí instance cílem Is nebo IsNot operátor, výchozí instance se nevytvořila. Proto je možné otestovat, zda je Nothing výchozí instance nebo nějaký jiný odkaz, aniž by způsobila vytvoření výchozí instance.
Výchozí instance mají usnadnit odkazování na výchozí instanci mimo třídu, která má výchozí instanci. Použití výchozí instance z třídy, která ji definuje, může způsobit nejasnosti o tom, na kterou instanci se odkazuje, tj. výchozí instance nebo aktuální instance. Například následující kód upraví pouze hodnotu x ve výchozí instanci, i když je volána z jiné instance. Kód by tedy vytiskl hodnotu 5 místo 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
Chcete-li zabránit tomuto druhu záměny, není platné odkazovat na výchozí instanci z metody instance typu výchozí instance.
Výchozí názvy instancí a typů
Výchozí instance může být také přístupná přímo prostřednictvím názvu jeho typu. V tomto případě se v libovolném kontextu výrazu, kde název typu není povolen výraz E, kde E představuje plně kvalifikovaný název třídy s výchozí instancí, je změněn na E', kde E' představuje výraz, který načte výchozí vlastnost instance. Pokud například výchozí instance pro třídy odvozené z Form povolení přístupu k výchozí instanci prostřednictvím názvu typu, je následující kód ekvivalentní kódu v předchozím příkladu:
Module Main
Sub Main()
Form1.x = 10
Console.WriteLine(Form2.y)
End Sub
End Module
To také znamená, že výchozí instance, která je přístupná prostřednictvím názvu jeho typu, je také možné přiřadit prostřednictvím názvu typu. Například následující kód nastaví výchozí instanci Form1 na Nothing:
Module Main
Sub Main()
Form1 = Nothing
End Sub
End Module
Všimněte si, že význam E.I byly E reprezentovány třídou a I představuje sdílený člen se nezmění. Takový výraz stále přistupuje ke sdílenému členu přímo z instance třídy a neodkazuje na výchozí instanci.
Třídy skupin
Atribut Microsoft.VisualBasic.MyGroupCollectionAttribute označuje třídu skupiny pro řadu výchozích instancí. Atribut má čtyři parametry:
TypeToCollectParametr určuje základní třídu pro skupinu. Všechny okamžité třídy bez parametrů otevřeného typu, které jsou odvozeny od typu s tímto názvem (bez ohledu na parametry typu), budou mít automaticky výchozí instanci.CreateInstanceMethodNameParametr určuje metodu volání ve třídě skupiny pro vytvoření nové instance ve výchozí vlastnosti instance.DisposeInstanceMethodNameParametr určuje metodu volání ve třídě skupiny, která má likvidovat výchozí vlastnost instance, pokud je výchozí vlastnost instance přiřazena hodnotuNothing.DefaultInstanceAliasParametr specifikuje výrazE', který má nahradit název třídy, pokud jsou výchozí instance přístupné přímo prostřednictvím názvu jejich typu. Pokud jeNothingtento parametr nebo prázdný řetězec, výchozí instance tohoto typu skupiny nejsou přístupné přímo prostřednictvím názvu jejich typu. (Poznámka: Ve všech aktuálních implementacích jazykaDefaultInstanceAliasVisual Basic se parametr ignoruje s výjimkou kódu poskytnutého kompilátorem.)
Do stejné skupiny lze shromáždit více typů oddělením názvů typů a metod v prvních třech parametrech pomocí čárek. V každém parametru musí být stejný počet položek a prvky seznamu se shodují v pořadí. Například následující deklarace atributu shromažďuje typy odvozené z C1nebo C2C3 do jedné skupiny:
<Microsoft.VisualBasic.MyGroupCollection("C1, C2, C3", _
"CreateC1, CreateC2, CreateC3", _
"DisposeC1, DisposeC2, DisposeC3", "My.Cs")>
Public NotInheritable Class MyCs
...
End Class
Podpis metody create musí být ve formuláři Shared Function <Name>(Of T As {New, <Type>})(Instance Of T) As T. Metoda dispose musí být ve formuláři Shared Sub <Name>(Of T As <Type>)(ByRef Instance Of T). Proto může být třída skupiny pro příklad v předchozí části deklarována takto:
<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
Pokud zdrojový soubor deklaroval odvozenou třídu Form1, vygenerovaná třída skupiny by byla ekvivalentní:
<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
Extension Method Collection
Rozšiřující metody pro výraz E.I přístupu člena jsou shromažďovány shromážděním všech metod rozšíření s názvem I , které jsou k dispozici v aktuálním kontextu:
- Nejprve se zkontroluje každý vnořený typ obsahující výraz, počínaje od nejvnitřnějšího a od nejkrajnějšího.
- Pak se zkontroluje každý vnořený obor názvů, který začíná od nejvnitřnějšího a přejde do vnějšího oboru názvů.
- Importy ve zdrojovém souboru se pak zkontrolují.
- Pak se kontrolují importy definované prostředím kompilace.
Rozšiřující nativní převod z cílového typu výrazu na typ prvního parametru metody rozšíření se shromažďuje pouze v případě, že existuje rozšiřující nativní převod. A na rozdíl od vazby regulárního jednoduchého výrazu názvu vyhledávání shromažďuje všechny rozšiřující metody; kolekce se při nalezení metody rozšíření nezastaví. Například:
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
V tomto příkladu, i když N2C1Extensions.M1 je nalezen dříve N1C1Extensions.M1, oba jsou považovány za rozšiřující metody. Po shromáždění všech metod rozšíření se pak zkrátí. Currying přebírá cíl volání metody rozšíření a použije ho na volání metody rozšíření, což vede k novému podpisu metody s odebraným prvním parametrem (protože byl zadán). Například:
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
V předchozím příkladu je výsledek vExt1.M použití metody signatura Sub M(y As Integer)metody .
Kromě odebrání prvního parametru metody rozšíření curry také odebere všechny parametry typu metody, které jsou součástí typu prvního parametru. Při zakřivení metody rozšíření s parametrem typu metody se u prvního parametru použije odvození typu a výsledek se opraví pro všechny parametry typu, které jsou odvozeny. Pokud odvození typu selže, metoda se ignoruje. Například:
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
V předchozím příkladu je výsledek vExt1.M použití metody signatura Sub M(Of U)(y As U)metody, protože parametr T typu je odvozen jako výsledek kariingu a je nyní opraven. Vzhledem k tomu, že parametr U typu nebyl odvozen jako součást kariingu, zůstává otevřený parametr. Podobně, protože parametr T typu je odvozen v důsledku použití v na Ext2.M, typ parametru y se stane pevný jako Integer. Nebude odvozovat žádný jiný typ. Při zakřivení podpisu se použijí také všechna omezení s výjimkou New omezení. Pokud omezení nejsou splněna nebo závisí na typu, který nebyl odvozen jako součást kariingu, je metoda rozšíření ignorována. Například:
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
Poznámka. Jedním z hlavních důvodů, proč provádět currying rozšiřujících metod, je, že umožňuje dotazovacím výrazům odvodit typ iterace před vyhodnocením argumentů metodou vzoru dotazu. Vzhledem k tomu, že většina metod vzorů dotazů má výrazy lambda, které vyžadují odvozování typu sami, značně zjednodušuje proces vyhodnocování výrazu dotazu.
Na rozdíl od normální dědičnosti rozhraní jsou k dispozici rozšiřující metody, které rozšiřují dvě rozhraní, která vzájemně nesouvisí, pokud nemají stejný složený podpis:
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
Nakonec je důležité si uvědomit, že metody rozšíření se při provádění pozdní vazby nepovažují:
Module Test
Sub Main()
Dim o As Object = ...
' Ignores extension methods
o.M1()
End Sub
End Module
Výrazy přístupu členů slovníku
Výraz přístupu člena slovníku slouží k vyhledání člena kolekce. Přístup člena slovníku má formu E!I, kde E je výraz, který je klasifikován jako hodnota a I je identifikátor.
DictionaryAccessExpression
: Expression? '!' IdentifierOrKeyword
;
Typ výrazu musí mít výchozí vlastnost indexovanou jedním String parametrem. Výraz E!I přístupu člena slovníku je transformován na výraz E.D("I"), kde D je výchozí vlastnost E. Například:
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
Pokud je zadaná vykřičník bez výrazu, předpokládá se výraz z bezprostředně obsahujícího With příkazu. Pokud neexistuje žádný příkaz obsahující With , dojde k chybě v době kompilace.
Výrazy volání
Výraz vyvolání se skládá z cíle vyvolání a volitelného seznamu argumentů.
InvocationExpression
: Expression ( OpenParenthesis ArgumentList? CloseParenthesis )?
;
ArgumentList
: PositionalArgumentList
| PositionalArgumentList Comma NamedArgumentList
| NamedArgumentList
;
PositionalArgumentList
: Expression? ( Comma Expression? )*
;
NamedArgumentList
: IdentifierOrKeyword ColonEquals Expression
( Comma IdentifierOrKeyword ColonEquals Expression )*
;
Cílový výraz musí být klasifikován jako skupina metod nebo hodnota, jejíž typ je typu delegáta. Pokud je cílovým výrazem hodnota, jejíž typ je typu delegáta, stane se cílem vyvolání výrazu skupina metod pro Invoke člena typu delegáta a cílový výraz se stane přidruženým cílovým výrazem skupiny metod.
Seznam argumentů má dva oddíly: poziční argumenty a pojmenované argumenty.
Poziční argumenty jsou výrazy a musí předcházet libovolným pojmenovanými argumenty.
Pojmenované argumenty začínají identifikátorem, který se může shodovat s klíčovými slovy a výrazem := .
Pokud skupina metod obsahuje pouze jednu přístupnou metodu, včetně metod instance a rozšíření, a tato metoda nepřijímá žádné argumenty a je funkcí, pak je skupina metod interpretována jako vyvolání výraz s prázdným seznamem argumentů a výsledek se použije jako cíl vyvolání výrazu se zadanými seznamy argumentů. Například:
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
V opačném případě se rozlišení přetížení použije u metod pro výběr nejvhodnější metody pro daný seznam argumentů. Pokud je nejvhodnější metodou funkce, výsledek vyvolání výrazu je klasifikován jako hodnota zadaná jako návratový typ funkce. Pokud je nejvhodnější metoda podprogram, výsledek se klasifikuje jako void. Pokud je nejvhodnější metoda částečnou metodou, která neobsahuje tělo, pak se vyvolání výraz ignoruje a výsledek se klasifikuje jako void.
U výrazu vyvolání s časnou vazbou se argumenty vyhodnocují v pořadí, v jakém jsou odpovídající parametry deklarovány v cílové metodě. U výrazu přístupu člena s pozdní vazbou se vyhodnocují v pořadí, v jakém se zobrazují ve výrazu přístupu člena: viz Oddíl Late-Bound Výrazy.
Řešení přetížené metody:
V případě řešení přetížení specifika členů/typů zadaných seznamem argumentů, genericity, použitelnosti pro seznam argumentů, předávání argumentů a výběr argumentů pro volitelné parametry, podmíněné metody a odvození argumentů typu: viz řešení přetížení oddílu.
Výrazy indexu
Výraz indexu má za následek prvek pole nebo přetřídí skupinu vlastností do přístupu k vlastnosti. Výraz indexu se skládá z výrazu v pořadí, výrazu, levých závorek, seznamu argumentů indexu a pravou závorku.
IndexExpression
: Expression OpenParenthesis ArgumentList? CloseParenthesis
;
Cíl výrazu indexu musí být klasifikován jako skupina vlastností nebo hodnota. Výraz indexu se zpracuje takto:
Pokud je cílový výraz klasifikován jako hodnota a pokud jeho typ není typ pole,
ObjectneboSystem.Array, typ musí mít výchozí vlastnost. Index se provádí ve skupině vlastností, která představuje všechny výchozí vlastnosti typu. I když není platné deklarovat výchozí vlastnost bez parametrů v jazyce Visual Basic, mohou jiné jazyky povolit deklarování takové vlastnosti. V důsledku toho je indexování vlastnosti bez argumentů povoleno.Pokud výsledkem výrazu je hodnota typu pole, musí být počet argumentů v seznamu argumentů stejný jako pořadí typu pole a nesmí obsahovat pojmenované argumenty. Pokud některý z indexů není za běhu platný,
System.IndexOutOfRangeExceptionvyvolá se výjimka. Každý výraz musí být implicitně konvertibilní na typInteger. Výsledkem výrazu indexu je proměnná v zadaném indexu a je klasifikována jako proměnná.Pokud je výraz klasifikován jako skupina vlastností, přetížit rozlišení se používá k určení, zda jedna z vlastností je použitelná pro seznam argumentů indexu. Pokud skupina vlastností obsahuje pouze jednu vlastnost, která má
Getpřístupový objekt a pokud tento přístup nepřijímá žádné argumenty, skupina vlastností se interpretuje jako výraz indexu s prázdným seznamem argumentů. Výsledek se použije jako cíl aktuálního výrazu indexu. Pokud nejsou k dispozici žádné vlastnosti, dojde k chybě v době kompilace. Jinak výsledkem výrazu je přístup k vlastnosti s přidruženým cílovým výrazem (pokud existuje) skupiny vlastností.Pokud je výraz klasifikován jako skupina vlastností s pozdní vazbou nebo jako hodnota, jejíž typ je
ObjectneboSystem.Array, zpracování výrazu indexu je odloženo do doby běhu a indexování je zpožděno. Výsledkem výrazu je přístup k vlastnosti s pozdní vazbou zadaný jakoObject. Přidružený cílový výraz je buď cílový výraz, pokud se jedná o hodnotu, nebo přidružený cílový výraz skupiny vlastností. Za běhu se výraz zpracuje takto:Pokud je výraz klasifikován jako skupina vlastností s pozdní vazbou, výraz může vést ke skupině metod, skupině vlastností nebo hodnotě (pokud je členem instance nebo sdílená proměnná). Pokud je výsledkem skupina metod nebo skupina vlastností, použije se na skupinu rozlišení přetížení, aby se určila správná metoda pro seznam argumentů. Pokud se rozlišení přetížení nezdaří,
System.Reflection.AmbiguousMatchExceptionvyvolá se výjimka. Výsledek se zpracuje buď jako přístup k vlastnosti, nebo jako vyvolání a výsledek se vrátí. Pokud je vyvolání podprogramu, je výsledkemNothing.Pokud je typ běhu cílového výrazu typ pole nebo
System.Arrayje výsledkem výrazu indexu hodnota proměnné v zadaném indexu.V opačném případě musí mít typ běhu výrazu výchozí vlastnost a index se provádí ve skupině vlastností, která představuje všechny výchozí vlastnosti typu. Pokud typ nemá výchozí vlastnost,
System.MissingMemberExceptionje vyvolán výjimka.
Nové výrazy
Operátor New slouží k vytvoření nových instancí typů. Existují čtyři formy výrazů New :
Výrazy pro vytváření objektů se používají k vytváření nových instancí typů tříd a typů hodnot.
Výrazy pro vytváření polí se používají k vytváření nových instancí typů polí.
Výrazy pro vytváření delegátů (které nemají odlišnou syntaxi od výrazů vytváření objektů) se používají k vytváření nových instancí typů delegátů.
Anonymní výrazy pro vytváření objektů se používají k vytvoření nových instancí anonymních typů tříd.
NewExpression
: ObjectCreationExpression
| ArrayExpression
| AnonymousObjectCreationExpression
;
Výraz New je klasifikován jako hodnota a výsledkem je nová instance typu.
výrazy Object-Creation
Výraz pro vytvoření objektu slouží k vytvoření nové instance typu třídy nebo typu struktury.
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
;
Typ výrazu vytvoření objektu musí být typ třídy, typ struktury nebo parametr typu s New omezením a nemůže být MustInherit třídou. Vzhledem k tomu, objekt vytvoření výrazu formuláře New T(A), kde T je typ třídy nebo typ struktury a A je volitelný seznam argumentů, přetížit rozlišení určuje správný konstruktor T volání. Parametr typu s New omezením se považuje za jediný konstruktor bez parametrů. Pokud není možné volat žádný konstruktor, dojde k chybě v době kompilace; jinak výsledkem výrazu je vytvoření nové instance T pomocí zvoleného konstruktoru. Pokud neexistují žádné argumenty, mohou být závorky vynechány.
Kde je instance přidělena, závisí na tom, zda je instance typ třídy nebo typ hodnoty.
New Instance typů tříd jsou vytvořeny v haldě systému, zatímco nové instance typů hodnot jsou vytvořeny přímo v zásobníku.
Výraz pro vytvoření objektu může volitelně zadat seznam inicializátorů členů za argumenty konstruktoru. Tyto inicializátory členů mají předponu klíčového slova Witha seznam inicializátorů se interpretuje, jako by byl v kontextu With příkazu. Například s ohledem na třídu:
Class Customer
Dim Name As String
Dim Address As String
End Class
Kód:
Module Test
Sub Main()
Dim x As New Customer() With { .Name = "Bob Smith", _
.Address = "123 Main St." }
End Sub
End Module
Přibližně odpovídá:
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
Každý inicializátor musí zadat název, který se má přiřadit, a název musí být proměnnouReadOnly jiné instance nebo vlastnost typu, který je vytvořen. Přístup člena nebude zpožděn, pokud je Objectvytvořen typ . Inicializátory nemusí používat Key klíčové slovo. Každý člen typu lze inicializovat pouze jednou. Výrazy inicializátoru se však mohou vzájemně odkazovat. Například:
Module Test
Sub Main()
Dim x As New Customer() With { .Name = "Bob Smith", _
.Address = .Name & " St." }
End Sub
End Module
Inicializátory jsou přiřazeny zleva doprava, takže pokud inicializátor odkazuje na člen, který ještě nebyl inicializován, uvidí po spuštění konstruktoru libovolnou hodnotu proměnné instance:
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
Inicializátory můžou být vnořené:
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
Pokud je vytvořený typ kolekce a má metodu instance s názvem Add (včetně rozšiřujících metod a sdílených metod), pak výraz pro vytvoření objektu může určit inicializátor kolekce předponu klíčového slova From. Výraz pro vytvoření objektu nemůže určit inicializátor člena i inicializátor kolekce. Každý prvek inicializátoru kolekce se předává jako argument vyvolání Add funkce. Například:
Dim list = New List(Of Integer)() From { 1, 2, 3, 4 }
odpovídá:
Dim list = New List(Of Integer)()
list.Add(1)
list.Add(2)
list.Add(3)
Pokud je prvek samotný inicializátor kolekce, každý prvek inicializátor dílčí kolekce bude předán jako individuální argument funkci Add . Například následující:
Dim dict = Dictionary(Of Integer, String) From { { 1, "One" },{ 2, "Two" } }
odpovídá:
Dim dict = New Dictionary(Of Integer, String)
dict.Add(1, "One")
dict.Add(2, "Two")
Toto rozšíření je vždy provedeno a je vždy provedeno pouze o jednu úroveň hluboko; následně jsou dílčí inicializátory považovány za literály pole. Například:
' 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 } } }
Výrazy pole
Výraz pole slouží k vytvoření nové instance typu pole. Existují dva typy maticových výrazů: výrazy pro vytváření polí a literály pole.
Výrazy pro vytváření polí
Pokud je zadán modifikátor inicializace velikosti pole, výsledný typ pole je odvozen odstraněním jednotlivých argumentů ze seznamu argumentů inicializace velikosti pole. Hodnota každého argumentu určuje horní mez odpovídající dimenze v nově přidělené instanci pole. Pokud má výraz neprázdný inicializátor kolekce, musí být každý argument v seznamu argumentů konstanta a délka pořadí a dimenze určené seznamem výrazů musí odpovídat hodnotám inicializátoru kolekce.
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 }
Pokud není zadán modifikátor inicializace velikosti pole, musí být název typu typ pole a inicializátor kolekce musí být prázdný nebo musí mít stejný počet úrovní vnoření jako pořadí zadaného typu pole. Všechny prvky v nejvnitřnější úrovni vnoření musí být implicitně konvertibilní na typ prvku pole a musí být klasifikovány jako hodnota. Počet prvků v každém inicializátoru vnořené kolekce musí vždy odpovídat velikosti ostatních kolekcí na stejné úrovni. Jednotlivé délky dimenzí jsou odvozeny z počtu prvků v každé z odpovídajících úrovní vnoření inicializátoru kolekce. Pokud je inicializátor kolekce prázdný, délka každé dimenze je nula.
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 } }
Nejkrajnější úroveň vnoření inicializátoru kolekce odpovídá levé dimenzi pole a nejvnitřnější úroveň vnoření odpovídá nejvíce pravé dimenzi. Příklad:
Dim array As Integer(,) = _
{ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }, { 8, 9 } }
Je ekvivalentní následujícímu:
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
Pokud je inicializátor kolekce prázdný (tj. ten, který obsahuje složené závorky, ale žádný seznam inicializátorů) a hranice dimenzí pole, které se inicializují, jsou známé, inicializátor prázdné kolekce představuje maticovou instanci zadané velikosti, kde byly všechny prvky inicializovány na výchozí hodnotu typu prvku. Pokud hranice dimenzí inicializovaného pole nejsou známy, inicializátor prázdné kolekce představuje instanci pole, ve které jsou všechny dimenze velikosti nula.
Pořadí a délka každé dimenze instance pole jsou konstantní po celou dobu životnosti instance. Jinými slovy, pořadí existující instance pole není možné změnit ani změnit jeho rozměry.
Literály pole
Literál pole označuje matici, jejíž typ prvku, pořadí a hranice jsou odvozeny z kombinace kontextu výrazu a inicializátoru kolekce. Toto je vysvětleno v přetřídění výrazu oddílu.
ArrayExpression
: ArrayCreationExpression
| ArrayLiteralExpression
;
ArrayCreationExpression
: 'New' NonArrayTypeName ArrayNameModifier CollectionInitializer
;
ArrayLiteralExpression
: CollectionInitializer
;
Například:
' 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}}
Formát a požadavky inicializátoru kolekce v literálu pole jsou přesně stejné jako pro inicializátor kolekce ve výrazu pro vytvoření pole.
Poznámka. Literál pole nevytváří pole sám o sobě; místo toho se jedná o přetřídění výrazu do hodnoty, která způsobí vytvoření pole. Převod například není možný, protože neexistuje žádný převod na Short()Integer() ; ale výraz CType({1,2,3},Short()) je možný, CType(new Integer() {1,2,3}, Short()) protože nejprve přetřídí literál pole do výrazu New Short() {1,2,3}pro vytvoření pole .
výrazy Delegate-Creation
Výraz pro vytvoření delegáta slouží k vytvoření nové instance typu delegáta. Argumentem výrazu pro vytvoření delegáta musí být výraz klasifikovaný jako ukazatel metody nebo metoda lambda.
Pokud je argument ukazatelem metody, musí být jedna z metod odkazovaných ukazatelem metody použitelná pro podpis typu delegáta. Metoda M se vztahuje na typ D delegáta, pokud:
MneníPartialnebo má tělo.Obě
MaDjsou funkce, neboDje podprogram.MaDmají stejný počet parametrů.Typy parametrů
Mkaždého mají převod z typu odpovídajícího typu parametruDa jejich modifikátory (tj.ByRef,ByVal) shody.Návratový
Mtyp , pokud existuje, má převod na návratovýDtyp .
Pokud ukazatel metody odkazuje na přístup s pozdní vazbou, předpokládá se, že opožděný přístup je funkce, která má stejný počet parametrů jako typ delegáta.
Pokud se nepoužívá striktní sémantika a ukazatel metody odkazuje pouze na jednu metodu, ale není použitelná kvůli tomu, že nemá žádné parametry a typ delegáta, je metoda považována za použitelnou a parametry nebo návratová hodnota jsou jednoduše ignorovány. Například:
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
Poznámka. Tato odpočinek je povolena pouze v případě, že se kvůli rozšiřujícím metodám nepoužívají striktní sémantika. Vzhledem k tomu, že rozšiřující metody jsou považovány pouze v případě, že běžná metoda nebyla použitelná, je možné, aby metoda instance bez parametrů skryla rozšiřující metodu s parametry pro účely delegování konstrukce.
Pokud je pro typ delegáta použitelná více než jedna metoda odkazovaná ukazatelem metody, použije se k výběru mezi kandidátskými metodami rozlišení přetížení. Typy parametrů delegáta se používají jako typy argumentů pro účely řešení přetížení. Pokud žádný kandidát metody není nejvhodnější, dojde k chybě v době kompilace. V následujícím příkladu je místní proměnná inicializována delegátem, který odkazuje na druhou Square metodu, protože tato metoda je vhodnější pro podpis a návratový DoubleFunctyp .
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
Pokud druhá Square metoda nebyla přítomna, byla by zvolena první Square metoda. Pokud jsou přísné sémantika určena prostředím kompilace nebo Option Strictpoté , dojde k chybě kompilace v případě, že nejpřesnější metoda odkazovaná ukazatelem metody je užší než podpis delegáta. Metoda M se považuje za užší než typ D delegáta, pokud:
Typ parametru
Mmá rozšiřující převod na odpovídající typ parametruD.Nebo návratový typ, pokud existuje,
Mmá zužující převod na návratovýDtyp .
Pokud jsou argumenty typu přidruženy k ukazateli metody, jsou považovány pouze metody se stejným počtem argumentů typu. Pokud nejsou k ukazateli metody přidruženy žádné argumenty typu, použije se při porovnávání podpisů s obecnou metodou odvození typu. Na rozdíl od ostatních normálních odvození typu se návratový typ delegáta používá při odvozování argumentů typu, ale návratové typy se stále nepovažují při určování nejmenšího obecného přetížení. Následující příklad ukazuje oba způsoby zadání argumentu typu výrazu delegate-creation:
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
V předchozím příkladu se pomocí obecné metody vytvořil instance jiného typu delegáta. Pomocí obecné metody je také možné vytvořit instanci vytvořeného typu delegáta. Například:
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
Pokud je argumentem výrazu delegate-creation metoda lambda, musí být metoda lambda použitelná pro podpis typu delegáta. Metoda L lambda se vztahuje na typ D delegáta, pokud:
Pokud
Lobsahuje parametry,Dmá stejný počet parametrů. (PokudLnemá žádné parametry, parametryDbudou ignorovány.)Typy parametrů
Lkaždého mají převod na typ odpovídajícího typu parametruDa jejich modifikátory (tj.ByRef,ByVal), které odpovídají.Pokud
Dje funkce, návratovýLtyp má převod na návratovýDtyp . (PokudDje podprogram, je vrácená hodnotaLignorována.)
Pokud je parametr typu parametru L vynechán, je odvozen typ odpovídajícího parametru D . Pokud má parametr L modifikátory polí nebo názvů s možnou hodnotou null, výsledkem chyby v době kompilace. Jakmile jsou k dispozici všechny typy L parametrů, je odvozen typ výrazu v metodě lambda. Například:
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
V některých situacích, kdy podpis delegáta přesně neodpovídá metodě lambda nebo podpisu metody, rozhraní .NET Framework nemusí nativně podporovat vytváření delegátů. V takovém případě se výraz metody lambda používá ke shodě obou metod. Například:
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
Výsledkem výrazu pro vytvoření delegáta je instance delegáta, která odkazuje na odpovídající metodu s přidruženým cílovým výrazem (pokud existuje) z výrazu ukazatele metody. Pokud je cílový výraz zadán jako typ hodnoty, pak je typ hodnoty zkopírován do systémové haldy, protože delegát může odkazovat pouze na metodu objektu v haldě. Metoda a objekt, na který delegát odkazuje, zůstávají konstantní po celou dobu životnosti delegáta. Jinými slovy, po vytvoření není možné změnit cíl ani objekt delegáta.
Anonymní výrazy Object-Creation
Výraz pro vytvoření objektu s inicializátory členů může také zcela vynechat název typu.
AnonymousObjectCreationExpression
: 'New' ObjectMemberInitializer
;
V takovém případě je anonymní typ vytvořen na základě typů a názvů členů inicializovaných jako součást výrazu. Například:
Module Test
Sub Main()
Dim Customer = New With { .Name = "John Smith", .Age = 34 }
Console.WriteLine(Customer.Name)
End Sub
End Module
Typ vytvořený anonymním výrazem pro vytvoření objektu je třída, která nemá žádné jméno, dědí přímo z Objecta má sadu vlastností se stejným názvem jako členové přiřazené v seznamu inicializátorů členů. Typ každé vlastnosti je odvozen pomocí stejných pravidel jako odvození typu místní proměnné. Generované anonymní typy také přepsat ToString, vrácení řetězcové reprezentace všech členů a jejich hodnot. (Přesný formát tohoto řetězce je nad rámec této specifikace).
Ve výchozím nastavení jsou vlastnosti vygenerované anonymním typem pro čtení i zápis. Vlastnost anonymního typu je možné označit jako jen pro čtení pomocí modifikátoru Key .
Key Modifikátor určuje, že pole lze použít k jedinečné identifikaci hodnoty, kterou anonymní typ představuje. Kromě toho, že vlastnost jen pro čtení, také způsobí, že anonymní typ přepíše Equals a GetHashCode implementuje rozhraní System.IEquatable(Of T) (vyplňování anonymního typu pro T). Členy jsou definovány takto:
Function Equals(obj As Object) As Boolean a Function Equals(val As T) As Boolean implementují se ověřením, že obě instance mají stejný typ a pak porovnávají jednotlivé Key členy pomocí Object.Equals. Pokud jsou všichni Key členové rovni, vrátí Equals , v opačném případě Equals vrátí TrueFalse.
Function GetHashCode() As Integer je implementováno tak, že pokud Equals je true pro dvě instance anonymního typu, GetHashCode vrátí stejnou hodnotu. Hodnota hash začíná počáteční hodnotou a potom pro každý Key člen vynásobí hodnotu hash hodnotou 31 a přičte Key hodnotu hash člena (poskytovanou GetHashCode) v případě, že člen není referenčním typem nebo typem hodnoty null s hodnotou Nothing.
Například typ vytvořený v příkazu:
Dim zipState = New With { Key .ZipCode = 98112, .State = "WA" }
vytvoří třídu, která vypadá přibližně takto (i když se přesná implementace může lišit):
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
Pro zjednodušení situace, kdy je z polí jiného typu vytvořen anonymní typ, lze názvy polí odvodit přímo z výrazů v následujících případech:
Jednoduchý výraz
xnázvu odvodí názevx.Výraz
x.ypřístupu člena odvodí názevy.Vyhledávací výraz
x!yslovníku odvodí názevy.Vyvolání nebo výraz indexu bez argumentů
x()odvodí názevx.Výraz
x.<y>přístupu člena XML ,x...<y>x.@yodvodí názevy.Výraz přístupu člena XML, který je cílem výrazu
x.<y>.zpřístupu člena, odvodí názevz.Výraz přístupu člena XML, který je cílem vyvolání nebo výraz indexu bez argumentů
x.<y>.z()odvodí názevz.Výraz přístupu člena XML, který je cílem vyvolání nebo výraz
x.<y>(0)indexu odvodí názevy.
Inicializátor se interpretuje jako přiřazení výrazu k odvozeného názvu. Například následující inicializátory jsou ekvivalentní:
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
Pokud je název člena odvozen, který je v konfliktu s existujícím členem typu, například GetHashCode, dojde k chybě v době kompilace. Na rozdíl od regulárních inicializátorů členů anonymní výrazy pro vytváření objektů neumožňují inicializátorům členů cyklické odkazy nebo odkazovat na člena před inicializacem. Například:
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
Pokud se ve stejné metodě vyskytují dva výrazy pro vytvoření anonymní třídy a vrátí stejný výsledný obrazec – pokud se pořadí vlastností, názvy vlastností a typy vlastností shodují – oba budou odkazovat na stejnou anonymní třídu. Obor metody instance nebo sdílené členské proměnné s inicializátorem je konstruktor, ve kterém je proměnná inicializována.
Poznámka. Je možné, že se kompilátor může rozhodnout sjednotit anonymní typy dále, například na úrovni sestavení, ale v tuto chvíli se na to nedá spoléhat.
Přetypování výrazů
Přetypování výrazu převede výraz na daný typ. Specifická klíčová slova přetypování přetypují výrazy do primitivních typů. Tři obecná klíčová slova přetypování, CTypeTryCast a DirectCast, převede výraz do typu.
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 a TryCast mají zvláštní chování. Z tohoto důvodu podporují pouze nativní převody. Cílový typ ve výrazu TryCast navíc nemůže být typ hodnoty. Uživatelem definované operátory převodu se při použití nepovažují DirectCastTryCast . (Poznámka: Sada převodů, která DirectCast a TryCast podpora jsou omezené, protože implementují "nativní převody CLR". Účelem DirectCast je poskytnout funkci instrukce "unbox" (rozbalit), zatímco účelem TryCast je poskytnout funkce instrukce "isinst". Vzhledem k tomu, že se mapují na instrukce CLR, podpora převodů, které přímo nepodporuje CLR, by porazit zamýšlený účel.)
DirectCast převede výrazy, které jsou zadány Object jinak než CType. Při převodu výrazu typuObject, jehož typ za běhu je primitivním typem hodnoty, vyvolá System.InvalidCastException výjimku, DirectCast pokud zadaný typ není stejný jako typ běhu výrazu nebo System.NullReferenceException pokud se výraz vyhodnotí jako Nothing. (Poznámka: Jak je uvedeno výše, mapuje se přímo na instrukce CLR "unbox", DirectCast pokud je Objecttyp výrazu . Naproti tomu CType se změní na volání pomocné rutiny modulu runtime k provedení převodu, aby bylo možné podporovat převody mezi primitivními typy. V případě, že Object je výraz převeden na primitivní typ hodnoty a typ skutečné instance odpovídá cílovému typu, DirectCast bude výrazně rychlejší než CType.)
TryCast převede výrazy, ale nevyvolá výjimku, pokud výraz nelze převést na cílový typ. Místo toho dojde k Nothing tomu, TryCast že výraz nelze převést za běhu. (Poznámka: Jak je uvedeno výše, TryCast mapuje se přímo na instrukce CLR "isinst". Kombinací kontroly typu a převodu do jedné operace TryCast může být levnější než provedení a TypeOf ... Is pak . CType)
Například:
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
Pokud z typu výrazu na zadaný typ neexistuje žádný převod, dojde k chybě v době kompilace. Jinak se výraz klasifikuje jako hodnota a výsledkem je hodnota vytvořená převodem.
Výrazy operátorů
Existují dva druhy operátorů.
Unární operátory přebírají jeden operand a používají notaci předpon (například -x).
Binární operátory mají dva operandy a používají infixační notaci (například x + y). S výjimkou relačních operátorů, které vždy vedou Booleank , operátor definovaný pro určitý typ výsledky v daném typu. Operandy operátoru musí být vždy klasifikovány jako hodnota; výsledek výrazu operátoru je klasifikován jako hodnota.
OperatorExpression
: ArithmeticOperatorExpression
| RelationalOperatorExpression
| LikeOperatorExpression
| ConcatenationOperatorExpression
| ShortCircuitLogicalOperatorExpression
| LogicalOperatorExpression
| ShiftOperatorExpression
| AwaitOperatorExpression
;
Priorita operátorů a asociativita
Pokud výraz obsahuje více binárních operátorů, priorita operátorů řídí pořadí, ve kterém se vyhodnocují jednotlivé binární operátory. Výraz se například vyhodnotí jako x + (y * z) proto, x + y * z že * operátor má vyšší prioritu + než operátor. Následující tabulka uvádí binární operátory v sestupném pořadí priorit:
| Kategorie | Operátoři |
|---|---|
| Primární | Všechny výrazy bez operátoru |
| Očekávat | Await |
| Umocňování | ^ |
| Unární negace |
+, - |
| Multiplikativní |
*, / |
| Celočíselné dělení | \ |
| Modul | Mod |
| Aditivní |
+, - |
| Zřetězení | & |
| Směna |
<<, >> |
| Relační |
=, <>, , >>=Like<<=, , IsIsNot |
| Logická negace | Not |
| Logická operace AND |
And, AndAlso |
| Logické NEBO |
Or, OrElse |
| Logický XOR | Xor |
Pokud výraz obsahuje dva operátory se stejnou prioritou, asociativita operátorů řídí pořadí provádění operací. Všechny binární operátory jsou asociativní zleva, což znamená, že operace se provádějí zleva doprava. Prioritu a asociativitu lze řídit pomocí závorek.
Operandy objektů
Kromě běžných typů podporovaných jednotlivými operátory podporují všechny operátory operandy typu Object. Operátory použité na Object operandy se zpracovávají podobně jako volání metody prováděné s Object hodnotami: volání metody s pozdní vazbou může být zvoleno, v takovém případě typ běhu operandů, nikoli typ kompilace, určuje platnost a typ operace. Pokud jsou striktní sémantika určena prostředím kompilace nebo Option Strictpomocí , všechny operátory s operandy typu Object způsobují chybu v době kompilace s výjimkou IsTypeOf...Isoperátorů a IsNot operátorů.
Pokud rozlišení operátoru určuje, že operace by měla být provedena pozdě vázaná, výsledek operace je výsledkem použití operátoru na typy operandů, pokud jsou typy operandů za běhu typy, které operátor podporuje.
Nothing Hodnota je považována za výchozí hodnotu typu druhého operandu ve výrazu binárního operátoru. Ve výrazu unárního operátoru nebo pokud jsou Nothing oba operandy ve výrazu binárního operátoru, je Integer typ operace nebo jediný typ výsledku operátoru, pokud operátor nezpůsobí Integer. Výsledek operace je vždy přetypován zpět na Object. Pokud typy operandu nemají platný operátor, System.InvalidCastException je vyvolán výjimka. Převody za běhu se provádějí bez ohledu na to, jestli jsou implicitní nebo explicitní.
Pokud by výsledkem číselné binární operace byla výjimka přetečení (bez ohledu na to, jestli je kontrola přetečení celého čísla zapnutá nebo vypnutá), typ výsledku se v případě potřeby upřednostní na další širší číselný typ. Představte si například následující kód:
Module Test
Sub Main()
Dim o As Object = CObj(CByte(2)) * CObj(CByte(255))
Console.WriteLine(o.GetType().ToString() & " = " & o)
End Sub
End Module
Vytiskne následující výsledek:
System.Int16 = 512
Pokud není k dispozici širší číselný typ pro uložení čísla, System.OverflowException vyvolá se výjimka.
Rozlišení operátoru
Při zadání typu operátoru a sady operandů určuje rozlišení operátoru, který má být použit pro operandy. Při překladu operátorů se uživatelem definované operátory nejprve považují za následující kroky:
Nejprve se shromažďují všechny kandidátské operátory. Kandidátské operátory jsou všechny uživatelem definované operátory konkrétního typu operátoru ve zdrojovém typu a všechny uživatelem definované operátory konkrétního typu v cílovém typu. Pokud souvisí typ zdroje a cílový typ, běžné operátory se považují pouze jednou.
Pak se rozlišení přetížení použije na operátory a operandy pro výběr nejvýraznějšího operátoru. V případě binárních operátorů to může vést k pozdnímu volání.
Při shromažďování kandidátských operátorů pro typ T?se místo toho použijí operátory typu T .
TVšechny uživatelem definované operátory, které zahrnují pouze nenulové typy hodnot, jsou také zdviženy. Operátor lifted používá verzi s možnou hodnotou null všech typů hodnot s výjimkou návratových IsTrue typů a IsFalse (které musí být Boolean). Lifted operátory se vyhodnocují převodem operandů na jejich nenulovou verzi, vyhodnocením uživatelem definovaného operátoru a následným převodem typu výsledku na jeho verzi s možnou hodnotou null. Pokud je Nothingoperand ether , výsledek výrazu je hodnota Nothing typovaná jako verze s možnou hodnotou null typu výsledku. Například:
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
Pokud je operátor binárním operátorem a jedním z operandů je odkazový typ, operátor se také zvedne, ale jakákoli vazba s operátorem způsobí chybu. Například:
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
Poznámka. Toto pravidlo existuje, protože bylo třeba zvážit, jestli chceme přidat odkazové typy šíření null v budoucí verzi, v takovém případě by se chování v případě binárních operátorů mezi těmito dvěma typy změnilo.
Stejně jako u převodů se uživatelem definované operátory vždy preferují před zvednutými operátory.
Při řešení přetížených operátorů mohou existovat rozdíly mezi třídami definovanými v jazyce Visual Basic a třídami definovanými v jiných jazycích:
V jiných jazycích ,
NotaAndmohouOrbýt přetíženy jak jako logické operátory, tak bitové operátory. Při importu z externího sestavení je buď formulář přijat jako platné přetížení pro tyto operátory. U typu, který definuje logické i bitové operátory, se však bude považovat pouze bitové implementace.V jiných jazycích a
<<může být přetížen jak jako operátory se znaménky,>>tak jako operátory bez znaménka. Při importu z externího sestavení je buď formulář přijat jako platné přetížení. U typu, který definuje operátory se znaménkem i bez znaménka, se však bude brát v úvahu pouze podepsaná implementace.Pokud není žádný uživatelem definovaný operátor nejvýraznější pro operandy, budou se zvažovat vnitřní operátory. Pokud není pro operandy definován žádný vnitřní operátor a oba operandy mají typ Object, operátor bude vyřešen s pozdní vazbou; v opačném případě dojde k chybě kompilace.
V předchozích verzích jazyka Visual Basic, pokud byl právě jeden operand typu Object, a žádné použitelné uživatelem definované operátory a žádné použitelné vnitřní operátory, pak se jednalo o chybu. Od verze Visual Basic 11 je nyní vyřešeno opožděné vazby. Například:
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
Typ T , který má vnitřní operátor, také definuje stejný operátor pro T?. Výsledek operátoru T? on bude stejný jako pro T, s tím rozdílem, že pokud je některý operand Nothing, bude výsledkem operátoru Nothing (tj. hodnota null se rozšíří). Pro účely překladu typu operace ? se odebere ze všech operandů, které je mají, určí se typ operace a ? přidá se k typu operace, pokud některý z operandů měl hodnotu null. Například:
Dim v1? As Integer = 10
Dim v2 As Long = 20
' Type of operation will be Long?
Console.WriteLine(v1 + v2)
Každý operátor uvádí vnitřní typy, pro které je definován, a typ operace prováděné s ohledem na typy operandu. Výsledek typu vnitřní operace se řídí těmito obecnými pravidly:
Pokud jsou všechny operandy stejného typu a operátor je pro tento typ definován, nedojde k žádnému převodu a použije se operátor pro tento typ.
Libovolný operand, jehož typ není definován pro operátor, je převeden pomocí následujících kroků a operátor je vyřešen proti novým typům:
Operand je převeden na další široký typ, který je definován pro operátor i operand a na který je implicitně konvertibilní.
Pokud takový typ neexistuje, operand se převede na další nejužší typ, který je definován pro operátor i operand a na který je implicitně konvertibilní.
Pokud takový typ neexistuje nebo převod nemůže nastat, dojde k chybě v době kompilace.
V opačném případě se operandy převedou na širší typy operandů a operátor pro tento typ. Pokud užší typ operandu nelze implicitně převést na širší typ operátoru, dojde k chybě v době kompilace.
Navzdory těmto obecným pravidlám je však v tabulkách výsledků operátoru vyvolána řada zvláštních případů.
Poznámka. Z důvodů formátování operátoru zkracují předdefinované názvy na první dva znaky. Takže "By" is , "UI" is ByteUInteger, "St" is String, etc. "Err" znamená, že pro dané typy operandů není definována žádná operace.
Aritmetické operátory
Operátory *, , ^Mod\+/a - operátory jsou aritmetické operátory.
ArithmeticOperatorExpression
: UnaryPlusExpression
| UnaryMinusExpression
| AdditionOperatorExpression
| SubtractionOperatorExpression
| MultiplicationOperatorExpression
| DivisionOperatorExpression
| ModuloOperatorExpression
| ExponentOperatorExpression
;
Aritmetické operace s plovoucí desetinnou čárkou mohou být prováděny s vyšší přesností než typ výsledku operace. Například některé hardwarové architektury podporují "rozšířený" nebo "dlouhý dvojitý" typ s plovoucí desetinnou čárkou s větší oblastí a přesností než Double typ, a implicitně provádět všechny operace s plovoucí desetinnou čárkou pomocí tohoto typu s vyšší přesností. Hardwarové architektury lze provádět za účelem provádění operací s plovoucí desetinnou čárkou s menší přesností pouze za nadměrné náklady při výkonu; Namísto vyžadování implementace pro snížení výkonu i přesnosti jazyka Visual Basic umožňuje použití vyšší přesnosti pro všechny operace s plovoucí desetinnou čárkou. Kromě poskytování přesnějších výsledků to má zřídka žádné měřitelné účinky. Nicméně, ve výrazech formuláře x * y / z, kde násobení vytváří výsledek, který je mimo Double rozsah, ale následné dělení vrátí dočasný výsledek zpět do Double oblasti, skutečnost, že výraz je vyhodnocen ve formátu vyššího rozsahu, může způsobit konečný výsledek se vytvoří místo nekonečna.
Unární operátor Plus
UnaryPlusExpression
: '+' Expression
;
Unární operátor plus je definován pro Byteoperátor , , SByte, UShortUIntegerShort, , Integer, ULong, , Long, Single, Doublea Decimal typy.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Pst | SB | Vedle | Pst | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob |
Unární mínus – operátor
UnaryMinusExpression
: '-' Expression
;
Operátor unární minus je definován pro následující typy:
SByte, Short, Integera Long. Výsledek se vypočítá odečtením operandu od nuly. Pokud je zapnutá kontrola přetečení celého čísla a hodnota operandu je maximální záporná SBytehodnota , Short, Integernebo Long, vyvolá System.OverflowException se výjimka. V opačném případě, pokud je hodnota operandu maximální záporná SByte, ShortInteger, nebo Long, výsledek je stejná hodnota a přetečení není hlášeno.
Single a Double. Výsledkem je hodnota operandu s invertovaným znakem, včetně hodnot 0 a nekonečna. Pokud je operand NaN, výsledek je také NaN.
Decimal. Výsledek se vypočítá odečtením operandu od nuly.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Pst | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob |
Operátor sčítání
Operátor sčítání vypočítá součet dvou operandů.
AdditionOperatorExpression
: Expression '+' LineTerminator? Expression
;
Operátor sčítání je definován pro následující typy:
Byte,SByte,UShort,Short,UInteger,Integer,ULongaLong. Pokud je zapnutá kontrola přetečení celého čísla a součet je mimo rozsah typu výsledku,System.OverflowExceptionvyvolá se výjimka. Jinak se přetečení neohlásí a zahodí se žádné významné bity s vysokým pořadím výsledku.SingleaDouble. Součet se vypočítá podle pravidel aritmetik IEEE 754.Decimal. Pokud je výsledná hodnota příliš velká pro reprezentaci v desítkovémSystem.OverflowExceptionformátu, vyvolá se výjimka. Pokud je výsledná hodnota příliš malá, aby představovala v desítkovém formátu, výsledek je 0.String. ObaStringoperandy jsou zřetězeny dohromady.Date. TypSystem.DateTimedefinuje přetížené operátory sčítání. Vzhledem k tomuSystem.DateTime, že je ekvivalentem vnitřníhoDatetypu, jsou tyto operátory k dispozici také proDatetento typ.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Pst | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob |
| SB | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |
| Od | Vedle | Pst | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||
| Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||
| Spojené státy | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||
| V | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||
| uživatelské rozhraní | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||
| Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||
| UL | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||||
| De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||||
| Si | Si | Udělej | Err | Err | Udělej | Ob | ||||||||||
| Dělat | Udělej | Err | Err | Udělej | Ob | |||||||||||
| Da | Sv | Err | Sv | Ob | ||||||||||||
| Ch | Sv | Sv | Ob | |||||||||||||
| Sv | Sv | Ob | ||||||||||||||
| Ob | Ob |
Operátor odčítání
Operátor odčítání odečte druhý operand od prvního operandu.
SubtractionOperatorExpression
: Expression '-' LineTerminator? Expression
;
Operátor odčítání je definován pro následující typy:
Byte,SByte,UShort,Short,UInteger,Integer,ULongaLong. Pokud je zapnutá kontrola přetečení celého čísla a rozdíl je mimo rozsah typu výsledku,System.OverflowExceptionvyvolá se výjimka. Jinak se přetečení neohlásí a zahodí se žádné významné bity s vysokým pořadím výsledku.SingleaDouble. Rozdíl se vypočítá podle pravidel aritmetik IEEE 754.Decimal. Pokud je výsledná hodnota příliš velká pro reprezentaci v desítkovémSystem.OverflowExceptionformátu, vyvolá se výjimka. Pokud je výsledná hodnota příliš malá, aby představovala v desítkovém formátu, výsledek je 0.Date. TypSystem.DateTimedefinuje přetížené operátory odčítání. Vzhledem k tomuSystem.DateTime, že je ekvivalentem vnitřníhoDatetypu, jsou tyto operátory k dispozici také proDatetento typ.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Pst | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob |
| SB | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |
| Od | Vedle | Pst | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||
| Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||
| Spojené státy | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||
| V | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||
| uživatelské rozhraní | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||
| Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||
| UL | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||||
| De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||||
| Si | Si | Udělej | Err | Err | Udělej | Ob | ||||||||||
| Dělat | Udělej | Err | Err | Udělej | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| Sv | Udělej | Ob | ||||||||||||||
| Ob | Ob |
Operátor násobení
Operátor násobení vypočítá součin dvou operandů.
MultiplicationOperatorExpression
: Expression '*' LineTerminator? Expression
;
Operátor násobení je definován pro následující typy:
Byte,SByte,UShort,Short,UInteger,Integer,ULongaLong. Pokud je kontrola přetečení celého čísla zapnutá a produkt je mimo rozsah typu výsledku,System.OverflowExceptionvyvolá se výjimka. Jinak se přetečení neohlásí a zahodí se žádné významné bity s vysokým pořadím výsledku.SingleaDouble. Produkt se vypočítá podle pravidel aritmetik IEEE 754.Decimal. Pokud je výsledná hodnota příliš velká pro reprezentaci v desítkovémSystem.OverflowExceptionformátu, vyvolá se výjimka. Pokud je výsledná hodnota příliš malá, aby představovala v desítkovém formátu, výsledek je 0.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Pst | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob |
| SB | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |
| Od | Vedle | Pst | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||
| Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||
| Spojené státy | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||
| V | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||
| uživatelské rozhraní | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||
| Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||
| UL | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||||
| De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||||
| Si | Si | Udělej | Err | Err | Udělej | Ob | ||||||||||
| Dělat | Udělej | Err | Err | Udělej | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| Sv | Udělej | Ob | ||||||||||||||
| Ob | Ob |
Operátory dělení
Operátory dělení vypočítá podíl dvou operandů. Existují dva operátory dělení: běžný operátor dělení s plovoucí desetinou čárkou a operátor dělení celého čísla.
DivisionOperatorExpression
: FPDivisionOperatorExpression
| IntegerDivisionOperatorExpression
;
FPDivisionOperatorExpression
: Expression '/' LineTerminator? Expression
;
IntegerDivisionOperatorExpression
: Expression '\\' LineTerminator? Expression
;
Operátor pravidelného dělení je definován pro následující typy:
SingleaDouble. Podíl se vypočítá podle pravidel aritmetik IEEE 754.Decimal. Pokud je hodnota pravého operandu nula, vyvoláSystem.DivideByZeroExceptionse výjimka. Pokud je výsledná hodnota příliš velká pro reprezentaci v desítkovémSystem.OverflowExceptionformátu, vyvolá se výjimka. Pokud je výsledná hodnota příliš malá, aby představovala v desítkovém formátu, je výsledek nula. Měřítko výsledku před zaokrouhlováním je nejblíže k upřednostňované škále, která zachová výsledek, který se rovná přesnému výsledku. Upřednostňované měřítko je měřítko prvního operandu, který je menší než měřítko druhého operandu.
Podle pravidel rozlišení normálního operátoru by normální dělení čistě mezi operandy typů, jako Byteje , IntegerShorta Long způsoboval by, že oba operandy budou převedeny na typ Decimal. Při řešení operátoru operátoru dělení, pokud není Decimalžádný typ , Double je však považován za užší než Decimal. Tato konvence se sleduje, protože Double dělení je efektivnější než Decimal dělení.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | De | Si | Udělej | Err | Err | Udělej | Ob |
| SB | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | De | Si | Udělej | Err | Err | Udělej | Ob | |
| Od | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | De | Si | Udělej | Err | Err | Udělej | Ob | ||
| Pst | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | De | Si | Udělej | Err | Err | Udělej | Ob | |||
| Spojené státy | Udělej | Udělej | Udělej | Udělej | Udělej | De | Si | Udělej | Err | Err | Udělej | Ob | ||||
| V | Udělej | Udělej | Udělej | Udělej | De | Si | Udělej | Err | Err | Udělej | Ob | |||||
| uživatelské rozhraní | Udělej | Udělej | Udělej | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||
| Hle | Udělej | Udělej | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||
| UL | Udělej | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||||
| De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||||
| Si | Si | Udělej | Err | Err | Udělej | Ob | ||||||||||
| Dělat | Udělej | Err | Err | Udělej | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| Sv | Udělej | Ob | ||||||||||||||
| Ob | Ob |
Celočíselná operátor dělení je definován pro Byte, , UShortSByte, ShortUInteger, , IntegerULong, a Long. Pokud je hodnota pravého operandu nula, vyvolá System.DivideByZeroException se výjimka. Dělení zaokrouhlí výsledek na nulu a absolutní hodnota výsledku je největší možné celé číslo, které je menší než absolutní hodnota podílu obou operandů. Výsledek je nulový nebo kladný, pokud dva operandy mají stejné znaménko a nula nebo záporné, pokud mají dva operandy opačné znaménka. Pokud je levý operand maximální zápornou , , nebo , a pravý operand je -1, dojde k přetečení; pokud je zapnutá kontrola přetečení celého čísla, System.OverflowException vyvolá se výjimka.LongIntegerShortSByte Jinak se přetečení neohlásí a výsledek je místo hodnoty levého operandu.
Poznámka. Vzhledem k tomu, že dva operandy pro nepodepsané typy budou vždy nulové nebo kladné, výsledek je vždy nula nebo kladná. Výsledkem výrazu bude vždy menší nebo rovna největšímu ze dvou operandů, není možné, aby došlo k přetečení. Jako taková kontrola přetečení celého čísla se neprovádí pro celočíselné dělení se dvěma celými čísly bez znaménka. Výsledkem je typ levého operandu.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Pst | SB | Pst | Pst | In | In | Hle | Hle | Hle | Hle | Hle | Hle | Err | Err | Hle | Ob |
| SB | SB | Pst | Pst | In | In | Hle | Hle | Hle | Hle | Hle | Hle | Err | Err | Hle | Ob | |
| Od | Vedle | Pst | USA | In | uživatelské rozhraní | Hle | UL | Hle | Hle | Hle | Err | Err | Hle | Ob | ||
| Pst | Pst | In | In | Hle | Hle | Hle | Hle | Hle | Hle | Err | Err | Hle | Ob | |||
| Spojené státy | USA | In | uživatelské rozhraní | Hle | UL | Hle | Hle | Hle | Err | Err | Hle | Ob | ||||
| V | In | Hle | Hle | Hle | Hle | Hle | Hle | Err | Err | Hle | Ob | |||||
| uživatelské rozhraní | uživatelské rozhraní | Hle | UL | Hle | Hle | Hle | Err | Err | Hle | Ob | ||||||
| Hle | Hle | Hle | Hle | Hle | Hle | Err | Err | Hle | Ob | |||||||
| UL | UL | Hle | Hle | Hle | Err | Err | Hle | Ob | ||||||||
| De | Hle | Hle | Hle | Err | Err | Hle | Ob | |||||||||
| Si | Hle | Hle | Err | Err | Hle | Ob | ||||||||||
| Dělat | Hle | Err | Err | Hle | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| Sv | Hle | Ob | ||||||||||||||
| Ob | Ob |
Mod – operátor
Operátor Mod (modulo) vypočítá zbytek dělení mezi dva operandy.
ModuloOperatorExpression
: Expression 'Mod' LineTerminator? Expression
;
Operátor Mod je definován pro následující typy:
Byte,SByte,UShort,Short, ,UInteger,ULongIntegeraLong. Výsledkemx Mod yje hodnota vytvořenáx - (x \ y) * y. Pokudyje nula,System.DivideByZeroExceptionvyvolá se výjimka. Operátor modulo nikdy nezpůsobí přetečení.SingleaDouble. Zbytek se vypočítá podle pravidel aritmetik IEEE 754.Decimal. Pokud je hodnota pravého operandu nula, vyvoláSystem.DivideByZeroExceptionse výjimka. Pokud je výsledná hodnota příliš velká pro reprezentaci v desítkovémSystem.OverflowExceptionformátu, vyvolá se výjimka. Pokud je výsledná hodnota příliš malá, aby představovala v desítkovém formátu, je výsledek nula.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Pst | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob |
| SB | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |
| Od | Vedle | Pst | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||
| Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||
| Spojené státy | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||
| V | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||
| uživatelské rozhraní | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||
| Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||
| UL | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||||
| De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||||
| Si | Si | Udělej | Err | Err | Udělej | Ob | ||||||||||
| Dělat | Udělej | Err | Err | Udělej | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| Sv | Udělej | Ob | ||||||||||||||
| Ob | Ob |
Operátor exponentiation
Operátor exponentace vypočítá první operand vyvolaný na mocninu druhého operandu.
ExponentOperatorExpression
: Expression '^' LineTerminator? Expression
;
Operátor exponentiation je definován pro typ Double. Hodnota se vypočítá podle pravidel aritmetik IEEE 754.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Err | Err | Udělej | Ob |
| SB | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Err | Err | Udělej | Ob | |
| Od | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Err | Err | Udělej | Ob | ||
| Pst | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Err | Err | Udělej | Ob | |||
| Spojené státy | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Err | Err | Udělej | Ob | ||||
| V | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Err | Err | Udělej | Ob | |||||
| uživatelské rozhraní | Udělej | Udělej | Udělej | Udělej | Udělej | Udělej | Err | Err | Udělej | Ob | ||||||
| Hle | Udělej | Udělej | Udělej | Udělej | Udělej | Err | Err | Udělej | Ob | |||||||
| UL | Udělej | Udělej | Udělej | Udělej | Err | Err | Udělej | Ob | ||||||||
| De | Udělej | Udělej | Udělej | Err | Err | Udělej | Ob | |||||||||
| Si | Udělej | Udělej | Err | Err | Udělej | Ob | ||||||||||
| Dělat | Udělej | Err | Err | Udělej | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| Sv | Udělej | Ob | ||||||||||||||
| Ob | Ob |
Relační operátory
Relační operátory porovnávají hodnoty s ostatními. Relační operátory jsou =, , ><><, , <=a >=.
RelationalOperatorExpression
: Expression '=' LineTerminator? Expression
| Expression '<' '>' LineTerminator? Expression
| Expression '<' LineTerminator? Expression
| Expression '>' LineTerminator? Expression
| Expression '<' '=' LineTerminator? Expression
| Expression '>' '=' LineTerminator? Expression
;
Všechny relační operátory mají za Boolean následek hodnotu.
Relační operátory mají následující obecný význam:
Operátor
=testuje, zda jsou dva operandy stejné.Operátor
<>testuje, zda jsou dva operandy nerovny.Operátor
<testuje, zda je první operand menší než druhý operand.Operátor
>testuje, zda je první operand větší než druhý operand.Operátor
<=testuje, zda je první operand menší nebo roven druhému operandu.Operátor
>=testuje, zda je první operand větší nebo roven druhému operandu.
Relační operátory jsou definovány pro následující typy:
Boolean. Operátory porovnávají hodnoty pravdy dvou operandů.Trueje považován za menší nežFalse, který odpovídá jejich číselným hodnotám.Byte,SByte,UShort,Short,UInteger,Integer,ULongaLong. Operátory porovnávají číselné hodnoty dvou integrálních operandů.SingleaDouble. Operátory porovnávají operandy podle pravidel standardu IEEE 754.Decimal. Operátory porovnávají číselné hodnoty dvou desetinných operandů.Date. Operátory vrátí výsledek porovnání dvou hodnot data a času.Char. Operátory vrátí výsledek porovnání dvou hodnot Unicode.String. Operátory vrátí výsledek porovnání obou hodnot pomocí binárního porovnání nebo porovnání textu. Použité porovnání je určeno prostředím kompilace a příkazemOption Compare. Binární porovnání určuje, zda je číselná hodnota Unicode každého znaku v každém řetězci stejná. Porovnání textu v kódu Unicode porovnává na základě aktuální jazykové verze používané v rozhraní .NET Framework. Při porovnávání řetězců je hodnota null ekvivalentní řetězcového literálu"".
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Bo | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Bo | Ob |
| SB | SB | Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |
| Od | Vedle | Pst | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||
| Pst | Pst | In | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||
| Spojené státy | USA | In | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||
| V | In | Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||
| uživatelské rozhraní | uživatelské rozhraní | Hle | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||
| Hle | Hle | De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||
| UL | UL | De | Si | Udělej | Err | Err | Udělej | Ob | ||||||||
| De | De | Si | Udělej | Err | Err | Udělej | Ob | |||||||||
| Si | Si | Udělej | Err | Err | Udělej | Ob | ||||||||||
| Dělat | Udělej | Err | Err | Udělej | Ob | |||||||||||
| Da | Da | Err | Da | Ob | ||||||||||||
| Ch | Ch | Sv | Ob | |||||||||||||
| Sv | Sv | Ob | ||||||||||||||
| Ob | Ob |
Operátor Like
Operátor Like určuje, zda řetězec odpovídá danému vzoru.
LikeOperatorExpression
: Expression 'Like' LineTerminator? Expression
;
Operátor Like je definován pro String typ. První operand je řetězec, který se porovnává, a druhý operand je vzor, který se má shodovat. Vzor je tvořen znaky Unicode. Následující sekvence znaků mají zvláštní významy:
?Znak odpovídá jakémukoli jednomu znaku.Znak
*odpovídá nule nebo více znaků.Znak
#odpovídá libovolné jednociferné číslici (0–9).Seznam znaků obklopených hranatými závorkami (
[ab...]) odpovídá jakémukoli jednomu znaku v seznamu.Seznam znaků obklopený hranatými závorkami a předponou vykřičníkem (
[!ab...]) odpovídá jakémukoli jednomu znaku, který není v seznamu znaků.Dva znaky v seznamu znaků oddělené spojovníkem (
-) určují rozsah znaků Unicode začínající prvním znakem a končícím druhým znakem. Pokud druhý znak není později v pořadí řazení než první znak, dojde k výjimce za běhu. Spojovník, který se zobrazí na začátku nebo konci seznamu znaků, určuje sám sebe.
Aby se shodovaly se speciálními znaky v levé závorce ([), otazníkem (?), znakem čísla (#) a hvězdičkou (*), musí je hranaté závorky uzavřít. Pravá hranatá závorka (]) se nedá použít v rámci skupiny, aby se shodovala sama se sebou, ale dá se použít mimo skupinu jako jednotlivý znak. Sekvence [] znaků je považována za řetězcový literál "".
Všimněte si, že porovnávání znaků a řazení seznamů znaků závisí na použitém typu porovnání. Pokud se používají binární porovnání, porovnávání znaků a řazení jsou založeny na číselných hodnotách Unicode. Pokud se používají porovnání textu, porovnávání znaků a řazení vychází z aktuálního národního prostředí používaného v rozhraní .NET Framework.
V některých jazycích speciální znaky v abecedě představují dva samostatné znaky a naopak. Například několik jazyků používá znak æ k reprezentaci znaků a a e jejich zobrazení společně, zatímco znaky ^ a O lze je použít k reprezentaci znaku Ô. Při použití porovnání Like textu operátor rozpozná takové kulturní ekvivalence. V takovém případě výskyt jednoho speciálního znaku v vzoru nebo řetězci odpovídá ekvivalentní dvouznakové sekvenci v druhém řetězci. Podobně jeden speciální znak v vzoru uzavřených v závorkách (sám o sobě, v seznamu nebo v oblasti) odpovídá ekvivalentní dvouznakové sekvenci v řetězci a naopak.
Ve výrazu Like , kde jsou oba operandy Nothing nebo jeden operand má vnitřní převod String a druhý operand je Nothing, Nothing je považován za prázdný řetězcový literál "".
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob |
| SB | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | |
| Od | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | ||
| Pst | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | |||
| Spojené státy | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | ||||
| V | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | |||||
| uživatelské rozhraní | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | ||||||
| Hle | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | |||||||
| UL | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | ||||||||
| De | Sv | Sv | Sv | Sv | Sv | Sv | Ob | |||||||||
| Si | Sv | Sv | Sv | Sv | Sv | Ob | ||||||||||
| Dělat | Sv | Sv | Sv | Sv | Ob | |||||||||||
| Da | Sv | Sv | Sv | Ob | ||||||||||||
| Ch | Sv | Sv | Ob | |||||||||||||
| Sv | Sv | Ob | ||||||||||||||
| Ob | Ob |
Operátor zřetězení
ConcatenationOperatorExpression
: Expression '&' LineTerminator? Expression
;
Operátor zřetězení je definován pro všechny vnitřní typy, včetně verzí s možnou hodnotou null vnitřních hodnot. Je také definován pro zřetězení mezi typy uvedené výše a System.DBNull, což je považováno Nothing za řetězec. Operátor zřetězení převede všechny jeho operandy na String; ve výrazu jsou všechny převody String považovány za rozšiřující bez ohledu na to, zda se používají striktní sémantika. Hodnota System.DBNull je převedena na literál Nothing zadaný jako String. Typ hodnoty null, jehož hodnota je Nothing také převedena na literál Nothing zadaný jako String, místo vyvolání chyby za běhu.
Operace zřetězení vede k řetězci, který je zřetězením dvou operandů v pořadí odleva doprava. Hodnota Nothing je považována za prázdný řetězcový literál "".
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob |
| SB | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | |
| Od | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | ||
| Pst | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | |||
| Spojené státy | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | ||||
| V | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | |||||
| uživatelské rozhraní | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | ||||||
| Hle | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | |||||||
| UL | Sv | Sv | Sv | Sv | Sv | Sv | Sv | Ob | ||||||||
| De | Sv | Sv | Sv | Sv | Sv | Sv | Ob | |||||||||
| Si | Sv | Sv | Sv | Sv | Sv | Ob | ||||||||||
| Dělat | Sv | Sv | Sv | Sv | Ob | |||||||||||
| Da | Sv | Sv | Sv | Ob | ||||||||||||
| Ch | Sv | Sv | Ob | |||||||||||||
| Sv | Sv | Ob | ||||||||||||||
| Ob | Ob |
Logické operátory
Operátory And, Not, Ora Xor jsou volána logické operátory.
LogicalOperatorExpression
: 'Not' Expression
| Expression 'And' LineTerminator? Expression
| Expression 'Or' LineTerminator? Expression
| Expression 'Xor' LineTerminator? Expression
;
Logické operátory se vyhodnocují takto:
BooleanTyp:Logická
Andoperace se provádí na svých dvou operandech.Na svém operandu se provádí logická
Notoperace.Logická
Oroperace se provádí na svých dvou operandech.Logická exkluzivní
Oroperace se provádí na svých dvou operandech.
Pro
Byte, ,SByte,UShort,UIntegerShort,Integer,ULongLonga všechny výčtové typy, se zadaná operace provádí na každém bitu binární reprezentace dvou operandů:And: Výsledek bitu je 1, pokud jsou oba bity 1; jinak je bit výsledku 0.Not: Bit výsledku je 1, pokud je bit 0; jinak je bit výsledku 1.Or: Výsledek bitu je 1, pokud je jeden bit 1; jinak je bit výsledku 0.Xor: Výsledek bitu je 1, pokud je jeden bit 1, ale ne oba bity; jinak je výsledek 0 (to znamená 1Xor0 = 1, 1Xor1 = 0).
Pokud logické operátory
AndaOrjsou pro typBoolean?zvednuty , jsou rozšířeny tak, aby zahrnovaly logickou logiku se třemi hodnotami, například:Andvyhodnotí hodnotu true, pokud jsou oba operandy pravdivé; false pokud jeden z operandů je false;Nothingjinak.Orvyhodnotí hodnotu true, pokud je jeden operand pravdivý; False je oba operandy false;Nothingjinak.
Například:
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
Poznámka. V ideálním případě by logické operátory And a Or byly by zvednuty pomocí tříhodnotové logiky pro libovolný typ, který lze použít v logickém výrazu (tj. typu, který implementuje IsTrue a IsFalse), stejným způsobem jako AndAlso a OrElse zkratový obvod napříč libovolným typem, který lze použít v logickém výrazu. Tříhodnotové zvedání se bohužel používá pouze u Boolean?, takže uživatelem definované typy, které chtějí logiku se třemi hodnotami, musí to provést ručně definováním And a Or operátory pro jejich verzi s možnou hodnotou null.
Z těchto operací nejsou možné přetečení. Operátory výčtového typu provádí bitové operace u základního typu výčtového typu, ale návratová hodnota je výčtový typ.
Typ operace není:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | SB | Vedle | Pst | USA | In | uživatelské rozhraní | Hle | UL | Hle | Hle | Hle | Err | Err | Hle | Ob |
A nebo typ operace Xor:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Bo | SB | Pst | Pst | In | In | Hle | Hle | Hle | Hle | Hle | Hle | Err | Err | Bo | Ob |
| SB | SB | Pst | Pst | In | In | Hle | Hle | Hle | Hle | Hle | Hle | Err | Err | Hle | Ob | |
| Od | Vedle | Pst | USA | In | uživatelské rozhraní | Hle | UL | Hle | Hle | Hle | Err | Err | Hle | Ob | ||
| Pst | Pst | In | In | Hle | Hle | Hle | Hle | Hle | Hle | Err | Err | Hle | Ob | |||
| Spojené státy | USA | In | uživatelské rozhraní | Hle | UL | Hle | Hle | Hle | Err | Err | Hle | Ob | ||||
| V | In | Hle | Hle | Hle | Hle | Hle | Hle | Err | Err | Hle | Ob | |||||
| uživatelské rozhraní | uživatelské rozhraní | Hle | UL | Hle | Hle | Hle | Err | Err | Hle | Ob | ||||||
| Hle | Hle | Hle | Hle | Hle | Hle | Err | Err | Hle | Ob | |||||||
| UL | UL | Hle | Hle | Hle | Err | Err | Hle | Ob | ||||||||
| De | Hle | Hle | Hle | Err | Err | Hle | Ob | |||||||||
| Si | Hle | Hle | Err | Err | Hle | Ob | ||||||||||
| Dělat | Hle | Err | Err | Hle | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| Sv | Hle | Ob | ||||||||||||||
| Ob | Ob |
Logické operátory s zkratem
Operátory AndAlso jsou zkratkové verze And a Or logické operátory.OrElse
ShortCircuitLogicalOperatorExpression
: Expression 'AndAlso' LineTerminator? Expression
| Expression 'OrElse' LineTerminator? Expression
;
Vzhledem k jejich krátkodobému chování se druhý operand nevyhodnocuje za běhu, pokud je výsledek operátoru známý po vyhodnocení prvního operandu.
Logické operátory zkratování se vyhodnocují takto:
Pokud se první operand operace
AndAlsovyhodnotíFalsejako nebo vrátí hodnotu True z operátoruIsFalse, vrátí výraz první operand. V opačném případě se vyhodnotí druhý operand a na dvou výsledcích se provede logickáAndoperace.Pokud se první operand operace
OrElsevyhodnotíTruejako nebo vrátí hodnotu True z operátoruIsTrue, vrátí výraz první operand. V opačném případě se vyhodnotí druhý operand a logickáOroperace se provede se svými dvěma výsledky.
Operátory AndAlso jsou OrElse definovány pro typ Boolean, nebo pro jakýkoli typ T , který přetěžuje následující operátory:
Public Shared Operator IsTrue(op As T) As Boolean
Public Shared Operator IsFalse(op As T) As Boolean
a také přetížení odpovídajícího And operátoru nebo Or operátoru:
Public Shared Operator And(op1 As T, op2 As T) As T
Public Shared Operator Or(op1 As T, op2 As T) As T
Při vyhodnocování AndAlso nebo OrElse operátorů se první operand vyhodnotí pouze jednou a druhý operand se buď nevyhodnotí, nebo se vyhodnotí přesně jednou. Představte si například následující kód:
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
Vytiskne následující výsledek:
And: False True
Or: True False
AndAlso: False
OrElse: True
Ve zdvižené formě AndAlso a OrElse operátorů, pokud byl první operand null Boolean?, je vyhodnocen druhý operand, ale výsledek je vždy null Boolean?.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob |
| SB | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | |
| Od | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | ||
| Pst | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | |||
| Spojené státy | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | ||||
| V | Bo | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | |||||
| uživatelské rozhraní | Bo | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | ||||||
| Hle | Bo | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | |||||||
| UL | Bo | Bo | Bo | Bo | Err | Err | Bo | Ob | ||||||||
| De | Bo | Bo | Bo | Err | Err | Bo | Ob | |||||||||
| Si | Bo | Bo | Err | Err | Bo | Ob | ||||||||||
| Dělat | Bo | Err | Err | Bo | Ob | |||||||||||
| Da | Err | Err | Err | Err | ||||||||||||
| Ch | Err | Err | Err | |||||||||||||
| Sv | Bo | Ob | ||||||||||||||
| Ob | Ob |
Operátory shift
Binární operátory << a >> provádějí operace posunu bitů.
ShiftOperatorExpression
: Expression '<' '<' LineTerminator? Expression
| Expression '>' '>' LineTerminator? Expression
;
Operátory jsou definovány pro operátory Byte, , ShortUShortSByte, UInteger, , IntegerULong a Long typy. Na rozdíl od ostatních binárních operátorů je typ výsledku operace posunu určen, jako by operátor byl unární operátor s pouze levým operandem. Typ pravého operandu musí být implicitně konvertibilní Integer na typ operace a není použit při určování typu výsledku operace.
Operátor << způsobí, že bity v prvním operandu se posunou doleva, počet míst určených velikostí posunu. Bity s vysokým pořadím mimo rozsah typu výsledku se zahodí a pozice uvolněných bitů s nízkým pořadím jsou vyplněné nulou.
Operátor >> způsobí posun bitů v prvním operandu doprava počet míst určených velikostí posunu. Bity s nízkým pořadím se zahodí a pozice uvolněných bitů s vysokým pořadím jsou nastaveny na nulu, pokud je levý operand kladný nebo záporný. Pokud je levý operand typu Byte, UShort, UIntegernebo ULong prázdné bity s vysokým pořadím jsou vyplněny nulou.
Operátory posunu posunou bity základní reprezentace prvního operandu o množství druhého operandu. Pokud je hodnota druhého operandu větší než počet bitů v prvním operandu nebo je záporná, vypočítá se velikost posunu tak, jak RightOperand And SizeMaskSizeMask je:
| LeftOperand – typ | SizeMask |
|---|---|
Byte, SByte |
7 (&H7) |
UShort, Short |
15 (&HF) |
UInteger, Integer |
31 (&H1F) |
ULong, Long |
63 (&H3F) |
Pokud je hodnota posunu nula, výsledek operace je shodný s hodnotou prvního operandu. Z těchto operací nejsou možné přetečení.
Typ operace:
| Bo | SB | Od | Pst | Spojené státy | V | uživatelské rozhraní | Hle | UL | De | Si | Dělat | Da | Ch | Sv | Ob |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Pst | SB | Vedle | Pst | USA | In | uživatelské rozhraní | Hle | UL | Hle | Hle | Hle | Err | Err | Hle | Ob |
Logické výrazy
Logický výraz je výraz, který se dá otestovat a zjistit, jestli je pravdivý nebo jestli je nepravda.
BooleanExpression
: Expression
;
Typ T lze použít v logickém výrazu, pokud v pořadí podle preference:
TjeBooleanneboBoolean?Tmá rozšiřující převod naBooleanTmá rozšiřující převod naBoolean?Tdefinuje dva pseudo operátory aIsTrueIsFalse.Tmá zužující převod naBoolean?, který nezahrnuje převod zBooleannaBoolean?.Tmá zužující převod naBoolean.
Poznámka. Je zajímavé si uvědomit, že pokud Option Strict je vypnutý, výraz, který má zužující převod na Boolean bude přijat bez chyby v době kompilace, ale jazyk bude stále preferovat IsTrue operátor, pokud existuje. Je to proto, že Option Strict pouze změní to, co je a není přijato jazykem, a nikdy nezmění skutečný význam výrazu.
IsTrue Proto musí být vždy preferován před zúžením převodu, bez ohledu na Option Strict.
Například následující třída nedefinuje rozšiřující převod na Boolean. V důsledku toho jeho použití v If příkazu způsobí volání operátoru 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
Pokud je logický výraz zadán jako nebo převeden na Boolean nebo Boolean?, je true, pokud hodnota je True a false jinak.
V opačném případě logický výraz volá IsTrue operátor a vrátí True operátor, pokud je vrácen True; jinak je nepravda (ale nikdy nevolá IsFalse operátor).
V následujícím příkladu Integer má zužující převod na Boolean, takže null Integer? má zužující převod na oba Boolean? (výnos null Boolean) a na Boolean (což vyvolá výjimku). Zužující převod je Boolean? preferován, a proto hodnota "i" jako logický výraz je tedy False.
Dim i As Integer? = Nothing
If i Then Console.WriteLine()
Výrazy lambda
Výraz lambda definuje anonymní metodu označovanou jako metoda lambda. Metody lambda usnadňují předávání "in-line" metod jiným metodám, které přebírají typy delegátů.
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'
;
Příklad:
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
vytiskne:
2 4 6 8
Výraz lambda začíná volitelnými modifikátory Async nebo Iterator, následovanými klíčovým slovem Function nebo Sub seznamem parametrů. Parametry ve výrazu lambda nelze deklarovat Optional nebo ParamArray nemohou mít atributy. Na rozdíl od běžných metod vynechání typu parametru pro metodu lambda automaticky neodvozuje Object. Místo toho, když je metoda lambda přetřízena, vynechané typy parametrů a ByRef modifikátory jsou odvozeny z cílového typu. V předchozím příkladu by výraz lambda mohl být zapsán jako Function(x) x * 2a odvodil by typ x , který má být Integer , když byla metoda lambda použita k vytvoření instance typu delegáta IntFunc . Na rozdíl od odvození místní proměnné, pokud parametr metody lambda vynechá typ, ale má modifikátor názvu pole nebo nullable, dojde k chybě kompilace.
Regulární výraz lambda je jeden s Async modifikátory ani Iterator modifikátory.
Výraz lambda iterátoru je jeden s modifikátorem Iterator a bez Async modifikátoru. Musí to být funkce. Pokud je přetříděná na hodnotu, lze ji přetřídět pouze na hodnotu typu delegáta, jejíž návratový typ je IEnumerator, nebo IEnumerableIEnumerator(Of T) nebo IEnumerable(Of T) pro některé Ta který nemá žádné parametry ByRef.
Asynchronní výraz lambda je jeden s modifikátorem Async a bez Iterator modifikátoru. Asynchronní sub lambda může být přetříděná pouze na hodnotu typu dílčího delegáta bez parametrů ByRef. Asynchronní funkce lambda může být přetříděná pouze na hodnotu typu delegáta funkce, jejíž návratový typ je Task nebo Task(Of T) pro některé Ta který nemá žádné parametry ByRef.
Výrazy lambda můžou být buď jednořádkové, nebo víceřádkové. Výrazy lambda s jedním řádkem Function obsahují jeden výraz, který představuje hodnotu vrácenou metodou lambda. Výrazy lambda s jedním řádkem Sub obsahují jeden příkaz bez jeho uzavření StatementTerminator. Například:
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
Jednořádkové konstrukty lambda se sváže méně těsně než všechny ostatní výrazy a příkazy. Proto je například "Function() x + 5" ekvivalentem "Function() (x+5)" místo "(Function() x) + 5". Aby nedocházelo k nejednoznačnosti, výraz lambda s jedním řádkem Sub nemusí obsahovat příkaz Dim nebo příkaz deklarace popisku. Kromě toho, pokud není uzavřen v závorkách, výraz lambda s jedním řádkem Sub nemusí být bezprostředně následovaný dvojtečku ":", přístupový operátor člena ".", operátor přístupu člena slovníku "!" nebo otevřená závorka "(". Nesmí obsahovat žádný blokový příkaz (With, SyncLock, If...EndIf, While, For, Do, Using) ani OnErrorResume.
Poznámka. Ve výrazu Function(i) x=ilambda je tělo interpretováno jako výraz (který testuje, zda x a i jsou rovny). Ale ve výrazu Sub(i) x=ilambda je tělo interpretováno jako příkaz (který je přiřazen ix).
Výraz lambda s více řádky obsahuje blok příkazu a musí končit odpovídajícím End příkazem (tj. End Function nebo End Sub). Stejně jako u běžných metod musí být příkaz a SubEnd příkazy metody Function lambda s více řádky na vlastních řádcích. Například:
' 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
Výrazy lambda s více řádky Function mohou deklarovat návratový typ, ale nemohou na něj vložit atributy. Pokud výraz lambda s více řádky Function deklaruje návratový typ, ale návratový typ lze odvodit z kontextu, ve kterém se výraz lambda použije , použije se tento návratový typ. V opačném případě se návratový typ funkce vypočítá takto:
V regulárním výrazu lambda je návratový typ dominantním typem výrazů ve všech
Returnpříkazech v bloku příkazu.V asynchronním výrazu lambda je
Task(Of T)návratový typ, kdeTje dominantním typem výrazů ve všechReturnpříkazech v bloku příkazu.Ve výrazu lambda iterátoru je
IEnumerable(Of T)návratový typ tam, kdeTje dominantním typem výrazů ve všechYieldpříkazech v bloku příkazu.
Například:
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
Ve všech případech platí, že pokud neexistují žádné Return příkazy (v uvedeném pořadí Yield), nebo pokud mezi nimi neexistuje dominantní typ a používá se striktní sémantika, dojde k chybě v době kompilace; jinak je dominantní typ implicitně Object.
Všimněte si, že návratový typ se vypočítá ze všech Return příkazů, i když nejsou dostupné. Například:
' Return type is Double
Dim x = Function()
Return 10
Return 10.50
End Function
Neexistuje žádná implicitní návratová proměnná, protože neexistuje žádný název proměnné.
Bloky příkazů uvnitř výrazů lambda s více řádky mají následující omezení:
On ErroraResumepříkazy nejsou povoleny, i kdyžTryjsou příkazy povolené.Statické místní hodnoty nelze deklarovat ve výrazech lambda s více řádky.
Z bloku příkazu výrazu lambda s více řádky není možné větvet ani z něj, i když v něm platí normální pravidla větvení. Například:
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
Výraz lambda je zhruba ekvivalentní anonymní metodě deklarované u obsahujícího typu. Počáteční příklad je zhruba ekvivalentní:
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
Uzavírky
Výrazy lambda mají přístup ke všem proměnným v oboru, včetně místních proměnných nebo parametrů definovaných v obsahující metodě a výrazech lambda. Když výraz lambda odkazuje na místní proměnnou nebo parametr, výraz lambda zachycuje proměnnou, na kterou odkazuje uzavření. Uzavření je objekt, který se nachází na haldě namísto zásobníku a při zachycení proměnné se všechny odkazy na proměnnou přesměrují na uzavření. To umožňuje výrazům lambda pokračovat v odkazech na místní proměnné a parametry i po dokončení obsahující metody. Například:
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
přibližně odpovídá:
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
Uzavření zaznamená novou kopii místní proměnné pokaždé, když zadá blok, ve kterém je místní proměnná deklarována, ale nová kopie se inicializuje s hodnotou předchozí kopie, pokud existuje. Například:
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
tiskne
1 2 3 4 5 6 7 8 9 10
Namísto
9 9 9 9 9 9 9 9 9 9
Vzhledem k tomu, že při zadávání bloku je nutné inicializovat uzavření, nesmí být do bloku s uzavřením mimo tento blok povolen GoTo , i když je povoleno Resume do bloku s uzavřením. Například:
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
Protože je nelze zachytit do uzavření, nemůže se v výrazu lambda objevit následující výraz:
Referenční parametry
Výrazy instance (
Me,MyClass,MyBase), pokud typMenení třída.
Členové anonymního výrazu pro vytvoření typu, pokud je výraz lambda součástí výrazu. Například:
' Error: Lambda cannot refer to anonymous type field
Dim x = New With { .a = 12, .b = Function() .a }
ReadOnly proměnné instance v konstruktorech instancí nebo ReadOnly sdílených proměnných ve sdílených konstruktorech, kde se proměnné používají v kontextu bez hodnoty. Například:
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
Výrazy dotazů
Výraz dotazu je výraz, který používá řadu operátorů dotazu na prvky dotazovatelné kolekce. Například následující výraz přebírá kolekci Customer objektů a vrací názvy všech zákazníků ve státě Washington:
Dim names = _
From cust In Customers _
Where cust.State = "WA" _
Select cust.Name
Výraz dotazu musí začínat operátorem FromAggregate nebo operátorem a může končit libovolným operátorem dotazu. Výsledek výrazu dotazu je klasifikován jako hodnota; typ výsledku výrazu závisí na typu výsledku posledního operátoru dotazu ve výrazu.
QueryExpression
: FromOrAggregateQueryOperator QueryOperator*
;
FromOrAggregateQueryOperator
: FromQueryOperator
| AggregateQueryOperator
;
QueryOperator
: FromQueryOperator
| AggregateQueryOperator
| SelectQueryOperator
| DistinctQueryOperator
| WhereQueryOperator
| OrderByQueryOperator
| PartitionQueryOperator
| LetQueryOperator
| GroupByQueryOperator
| JoinOrGroupJoinQueryOperator
;
JoinOrGroupJoinQueryOperator
: JoinQueryOperator
| GroupJoinQueryOperator
;
Proměnné rozsahu
Některé operátory dotazu představují speciální druh proměnné označované jako proměnná rozsahu. Proměnné rozsahu nejsou reálné proměnné; místo toho představují jednotlivé hodnoty během vyhodnocení dotazu ve vstupních kolekcích.
CollectionRangeVariableDeclarationList
: CollectionRangeVariableDeclaration ( Comma CollectionRangeVariableDeclaration )*
;
CollectionRangeVariableDeclaration
: Identifier ( 'As' TypeName )? 'In' LineTerminator? Expression
;
ExpressionRangeVariableDeclarationList
: ExpressionRangeVariableDeclaration ( Comma ExpressionRangeVariableDeclaration )*
;
ExpressionRangeVariableDeclaration
: Identifier ( 'As' TypeName )? Equals Expression
;
Proměnné rozsahu jsou vymezeny od operátoru úvodu dotazu na konec výrazu dotazu nebo na operátor dotazu, jako Select je například skrytí. Například v následujícím dotazu
Dim waCusts = _
From cust As Customer In Customers _
Where cust.State = "WA"
From Operátor dotazu zavádí proměnnou cust rozsahu, která Customer představuje každého zákazníka v kolekciCustomers. Následující Where operátor dotazu pak odkazuje na proměnnou cust rozsahu ve výrazu filtru a určí, jestli se má jednotlivý zákazník vyfiltrovat z výsledné kolekce.
Existují dva typy proměnných rozsahu: proměnné rozsahu kolekcí a proměnné rozsahu výrazů. Proměnné rozsahu kolekcí přebírají své hodnoty z prvků dotazovaných kolekcí. Výraz kolekce v deklaraci proměnné rozsahu kolekce musí být klasifikován jako hodnota, jejíž typ je dotazovatelný. Pokud je typ proměnné rozsahu kolekce vynechán, je odvozen jako typ elementu výrazu kolekce nebo Object pokud výraz kolekce neobsahuje typ elementu (tj. definuje pouze metodu Cast ). Pokud výraz kolekce nelze dotazovat (tj. typ prvku kolekce nelze odvodit), výsledky chyby v době kompilace.
Proměnná rozsahu výrazů je proměnná rozsahu, jejíž hodnota je vypočítána výrazem místo kolekce. V následujícím příkladu Select operátor dotazu zavádí proměnnou rozsahu výrazů s názvem cityState vypočítanou ze dvou polí:
Dim cityStates = _
From cust As Customer In Customers _
Select cityState = cust.City & "," & cust.State _
Where cityState.Length() < 10
Proměnná rozsahu výrazů není nutná k odkazování na jinou proměnnou rozsahu, i když taková proměnná může být pochybná. Výraz přiřazený proměnné rozsahu výrazů musí být klasifikován jako hodnota a musí být implicitně konvertibilní na typ proměnné rozsahu, pokud je zadán.
Pouze v operátoru Let může proměnná rozsahu výrazů mít zadaný typ. V jiných operátorech nebo pokud jeho typ není zadán, pak se k určení typu proměnné rozsahu použije odvození místního typu proměnné.
Proměnná rozsahu musí dodržovat pravidla pro deklarování místních proměnných s ohledem na stínování. Proměnná rozsahu proto nemůže skrýt název místní proměnné nebo parametru v ohraničující metodě nebo jiné proměnné rozsahu (pokud operátor dotazu výslovně skryje všechny aktuální proměnné rozsahu v oboru).
Typy s možností dotazování
Výrazy dotazů se implementují tak, že výraz přeloží na volání známých metod typu kolekce. Tyto dobře definované metody definují typ elementu dotazovatelné kolekce a také typy výsledků operátorů dotazu spouštěné v kolekci. Každý operátor dotazu určuje metodu nebo metody, do nichž je operátor dotazu obecně přeložen, i když konkrétní překlad závisí na implementaci. Metody jsou uvedeny ve specifikaci pomocí obecného formátu, který vypadá takto:
Function Select(selector As Func(Of T, R)) As CR
Následující platí pro metody:
Metoda musí být instance nebo člen rozšíření typu kolekce a musí být přístupná.
Metoda může být obecná, pokud je možné odvodit všechny argumenty typu.
Metoda může být přetížena, v takovém případě se rozlišení přetížení používá k určení přesně používané metody.
Místo typu delegáta může být použit jiný typ delegáta
Funcza předpokladu, že má stejný podpis, včetně návratového typu, jako odpovídajícíFunctyp.System.Linq.Expressions.Expression(Of D)Typ lze použít místo typu delegátaFuncza předpokladu, žeDje to typ delegáta, který má stejný podpis, včetně návratového typu, jako typ shodyFunc.Typ
Tpředstavuje typ prvku vstupní kolekce. Všechny metody definované typem kolekce musí mít stejný typ vstupního prvku, aby byl typ kolekce dotazovatelný.Typ
Spředstavuje typ prvku druhé vstupní kolekce v případě operátorů dotazu, které provádějí spojení.Typ
Kpředstavuje typ klíče v případě operátorů dotazu, které mají sadu proměnných rozsahu, které fungují jako klíče.Typ
Npředstavuje typ, který se používá jako číselný typ (i když může být uživatelem definovaným typem, nikoli vnitřní číselným typem).BTyp představuje typ, který lze použít v logickém výrazu.Typ
Rpředstavuje typ prvku kolekce výsledků, pokud operátor dotazu vytvoří kolekci výsledků.Rzávisí na počtu proměnných rozsahu v oboru na závěr operátoru dotazu. Pokud je v oboru jedna proměnná rozsahu, jednáRse o typ této proměnné rozsahu. V příkladuDim custNames = From c In Customers Select c.Namevýsledkem dotazu bude typ kolekce s typem
Stringprvku . Pokud je v oboru více proměnných rozsahu, je anonymníRtyp, který obsahuje všechny proměnné rozsahu v oboru jakoKeypole. V příkladu:Dim custNames = From c In Customers, o In c.Orders Select Name = c.Name, ProductName = o.ProductNameVýsledkem dotazu bude typ kolekce s typem elementu anonymního typu s vlastností jen pro čtení s názvem
NametypuStringa vlastností jen pro čtení s názvemProductNametypuString.Ve výrazu dotazu jsou anonymní typy vygenerované tak, aby obsahovaly proměnné rozsahu, transparentní, což znamená, že proměnné rozsahu jsou vždy dostupné bez kvalifikace. Například v předchozím příkladu byly proměnné rozsahu
caomohly být přístupné bez kvalifikace v operátoruSelectdotazu, i když typ elementu vstupní kolekce byl anonymní typ.CXTyp představuje typ kolekce, ne nutně vstupní typ kolekce, jehož typ prvku je nějaký typX.
Typ dotazovatelné kolekce musí splňovat jednu z následujících podmínek v pořadí podle preference:
Musí definovat odpovídající
Selectmetodu.Musí mít jednu z následujících metod.
Function AsEnumerable() As CT Function AsQueryable() As CTkteré lze volat k získání dotazovatelné kolekce. Pokud jsou k dispozici obě metody,
AsQueryableje vhodnější nežAsEnumerable.Musí mít metodu.
Function Cast(Of T)() As CTkteré lze volat s typem proměnné rozsahu pro vytvoření dotazovatelné kolekce.
Vzhledem k tomu, že určení typu prvku kolekce probíhá nezávisle na skutečné vyvolání metody, nelze určit použitelnost konkrétních metod. Proto při určování typu prvku kolekce, pokud existují metody instance, které odpovídají dobře známým metodám, jsou ignorovány všechny rozšiřující metody, které odpovídají dobře známým metodám.
K překladu operátoru dotazu dochází v pořadí, v jakém se ve výrazu vyskytují operátory dotazu. Není nutné, aby objekt kolekce implementovali všechny metody potřebné všemi operátory dotazu, i když každý objekt kolekce musí alespoň podporovat Select operátor dotazu. Pokud potřebná metoda není k dispozici, dojde k chybě v době kompilace. Při vytváření dobře známých názvů metod vazby se pro účely vícenásobné dědičnosti v rozhraních a vazbě metody rozšíření ignorují jiné metody než metody stínování, i když stále platí sémantika stínování. Například:
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
Výchozí indexer dotazů
Každý typ kolekce s možností dotazování, jehož typ elementu je T a nemá výchozí vlastnost, je považován za výchozí vlastnost v následujícím obecném formuláři:
Public ReadOnly Default Property Item(index As Integer) As T
Get
Return Me.ElementAtOrDefault(index)
End Get
End Property
Výchozí vlastnost lze odkazovat pouze pomocí výchozí syntaxe přístupu k vlastnostem; výchozí vlastnost nelze odkazovat na název. Například:
Dim customers As IEnumerable(Of Customer) = ...
Dim customerThree = customers(2)
' Error, no such property
Dim customerFour = customers.Item(4)
Pokud typ kolekce nemá ElementAtOrDefault člena, dojde k chybě v době kompilace.
Z operátoru dotazu
Operátor From dotazu zavádí proměnnou rozsahu kolekcí, která představuje jednotlivé členy kolekce, které se mají dotazovat.
FromQueryOperator
: LineTerminator? 'From' LineTerminator? CollectionRangeVariableDeclarationList
;
Například výraz dotazu:
From c As Customer In Customers ...
lze považovat za ekvivalent
For Each c As Customer In Customers
...
Next c
From Pokud operátor dotazu deklaruje více proměnných rozsahu kolekcí nebo není prvním From operátorem dotazu ve výrazu dotazu, každá nová proměnná rozsahu kolekcí je křížová připojena k existující sadě proměnných rozsahu. Výsledkem je, že dotaz se vyhodnocuje přes křížový součin všech prvků ve spojených kolekcích. Například výraz:
From c In Customers _
From e In Employees _
...
lze považovat za ekvivalentní:
For Each c In Customers
For Each e In Employees
...
Next e
Next c
a je přesně ekvivalentní:
From c In Customers, e In Employees ...
Proměnné rozsahu zavedené v předchozích operátorech dotazu lze použít v pozdějším From operátoru dotazu. Například v následujícím výrazu dotazu druhý From operátor dotazu odkazuje na hodnotu první proměnné rozsahu:
From c As Customer In Customers _
From o As Order In c.Orders _
Select c.Name, o
Více proměnných rozsahu v operátoru From dotazu nebo více From operátorů dotazu je podporováno pouze v případě, že typ kolekce obsahuje jednu nebo obě následující metody:
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
Kód
Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs, y In ys ...
je obecně přeložen do
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})...
Poznámka.
From není rezervované slovo.
Operátor dotazu join
Operátor Join dotazu spojí existující proměnné rozsahu s novou proměnnou rozsahu kolekcí a vytvoří jednu kolekci, jejíž prvky byly spojeny dohromady na základě výrazu rovnosti.
JoinQueryOperator
: LineTerminator? 'Join' LineTerminator? CollectionRangeVariableDeclaration
JoinOrGroupJoinQueryOperator? LineTerminator? 'On' LineTerminator? JoinConditionList
;
JoinConditionList
: JoinCondition ( 'And' LineTerminator? JoinCondition )*
;
JoinCondition
: Expression 'Equals' LineTerminator? Expression
;
Například:
Dim customersAndOrders = _
From cust In Customers _
Join ord In Orders On cust.ID Equals ord.CustomerID
Výraz rovnosti je omezen více než regulární výraz rovnosti:
Oba výrazy musí být klasifikovány jako hodnota.
Oba výrazy musí odkazovat alespoň na jednu proměnnou rozsahu.
Proměnná rozsahu deklarovaná v operátoru dotazu join musí být odkazována jedním z výrazů a tento výraz nesmí odkazovat na žádné jiné proměnné rozsahu.
Pokud typy těchto dvou výrazů nejsou úplně stejným typem, pak
Pokud je operátor rovnosti definován pro dva typy, oba výrazy jsou implicitně převedeny na něj a není
Object, pak převeďte oba výrazy na tento typ.Jinak pokud existuje dominantní typ, na který lze implicitně převést oba výrazy, převeďte oba výrazy na tento typ.
V opačném případě dojde k chybě kompilace.
Výrazy se porovnávají pomocí hodnot hash (tj. voláním GetHashCode()) místo pomocí operátorů rovnosti pro efektivitu. Operátor Join dotazu může ve stejném operátoru provádět více spojení nebo podmínek rovnosti.
Join Operátor dotazu je podporován pouze v případě, že typ kolekce obsahuje metodu:
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
Kód
Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs _
Join y In ys On x Equals y _
...
je obecně přeložen do
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})...
Poznámka:JoinOn a Equals nejsou vyhrazená slova.
Operátor dotazu Let
Operátor Let dotazu zavádí proměnnou rozsahu výrazů. To umožňuje výpočet přechodné hodnoty jednou, která se použije vícekrát v pozdějších operátorech dotazů.
LetQueryOperator
: LineTerminator? 'Let' LineTerminator? ExpressionRangeVariableDeclarationList
;
Například:
Dim taxedPrices = _
From o In Orders _
Let tax = o.Price * 0.088 _
Where tax > 3.50 _
Select o.Price, tax, total = o.Price + tax
lze považovat za ekvivalentní:
For Each o In Orders
Dim tax = o.Price * 0.088
...
Next o
Let Operátor dotazu je podporován pouze v případě, že typ kolekce obsahuje metodu:
Function Select(selector As Func(Of T, R)) As CR
Kód
Dim xs() As Integer = ...
Dim zs = From x In xs _
Let y = x * 10 _
...
je obecně přeložen do
Dim xs() As Integer = ...
Dim zs = _
xs.Select(Function(x As Integer) New With {x, .y = x * 10})...
Výběr operátoru dotazu
Operátor Select dotazu je jako Let operátor dotazu v tom, že zavádí proměnné rozsahu výrazů, Select ale operátor dotazu skryje aktuálně dostupné proměnné rozsahu místo jejich přidání. Typ proměnné rozsahu výrazů zavedené operátorem Select dotazu je také vždy odvozen pomocí pravidel odvození místního typu proměnné. Explicitní typ nelze zadat a pokud nelze odvodit žádný typ, dojde k chybě v době kompilace.
SelectQueryOperator
: LineTerminator? 'Select' LineTerminator? ExpressionRangeVariableDeclarationList
;
Například v dotazu:
Dim smiths = _
From cust In Customers _
Select name = cust.name _
Where name.EndsWith("Smith")
Where Operátor dotazu má přístup pouze k proměnné rozsahu name zavedené operátoremSelect; pokud Where se operátor pokusil odkazovat cust, došlo k chybě v době kompilace.
Namísto explicitního zadávání názvů proměnných rozsahu Select může operátor dotazu odvodit názvy proměnných rozsahu pomocí stejných pravidel jako výrazy pro vytváření objektů anonymního typu. Například:
Dim custAndOrderNames = _
From cust In Customers, ord In cust.Orders _
Select cust.name, ord.ProductName _
Where name.EndsWith("Smith")
Pokud název proměnné rozsahu není zadán a název nelze odvodit, dojde k chybě v době kompilace.
Select Pokud operátor dotazu obsahuje pouze jeden výraz, nedojde k žádné chybě, pokud název této proměnné rozsahu nelze odvodit, ale proměnná rozsahu je beznázvová. Například:
Dim custAndOrderNames = _
From cust In Customers, ord In cust.Orders _
Select cust.Name & " bought " & ord.ProductName _
Take 10
Pokud je v operátoru Select dotazu nejednoznačnost mezi přiřazením názvu proměnné rozsahu a výrazem rovnosti, je upřednostňované přiřazení názvu. Například:
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)
Každý výraz v operátoru Select dotazu musí být klasifikován jako hodnota.
Select Operátor dotazu se podporuje jenom v případě, že typ kolekce obsahuje metodu:
Function Select(selector As Func(Of T, R)) As CR
Kód
Dim xs() As Integer = ...
Dim zs = From x In xs _
Select x, y = x * 10 _
...
je obecně přeložen do
Dim xs() As Integer = ...
Dim zs = _
xs.Select(Function(x As Integer) New With {x, .y = x * 10})...
Operátor distinct query
Operátor Distinct dotazu omezuje hodnoty v kolekci pouze na hodnoty s odlišnými hodnotami, jak je určeno porovnáním typu prvku pro rovnost.
DistinctQueryOperator
: LineTerminator? 'Distinct' LineTerminator?
;
Například dotaz:
Dim distinctCustomerPrice = _
From cust In Customers, ord In cust.Orders _
Select cust.Name, ord.Price _
Distinct
vrátí pouze jeden řádek pro každou odlišnou dvojici názvu zákazníka a ceny objednávky, a to i v případě, že zákazník má více objednávek se stejnou cenou.
Distinct Operátor dotazu se podporuje jenom v případě, že typ kolekce obsahuje metodu:
Function Distinct() As CT
Kód
Dim xs() As Integer = ...
Dim zs = From x In xs _
Distinct _
...
je obecně přeložen do
Dim xs() As Integer = ...
Dim zs = xs.Distinct()...
Poznámka.
Distinct není rezervované slovo.
Where Query – operátor
Operátor Where dotazu omezuje hodnoty v kolekci na hodnoty, které splňují danou podmínku.
WhereQueryOperator
: LineTerminator? 'Where' LineTerminator? BooleanExpression
;
Operátor Where dotazu přebírá logický výraz, který se vyhodnocuje pro každou sadu hodnot proměnných rozsahu. Pokud je hodnota výrazu pravdivá, pak se hodnoty zobrazí ve výstupní kolekci, jinak se hodnoty přeskočí. Například výraz dotazu:
From cust In Customers, ord In Orders _
Where cust.ID = ord.CustomerID _
...
lze považovat za ekvivalent vnořené smyčky.
For Each cust In Customers
For Each ord In Orders
If cust.ID = ord.CustomerID Then
...
End If
Next ord
Next cust
Where Operátor dotazu se podporuje jenom v případě, že typ kolekce obsahuje metodu:
Function Where(predicate As Func(Of T, B)) As CT
Kód
Dim xs() As Integer = ...
Dim zs = From x In xs _
Where x < 10 _
...
je obecně přeložen do
Dim xs() As Integer = ...
Dim zs = _
xs.Where(Function(x As Integer) x < 10)...
Poznámka.
Where není rezervované slovo.
Operátory dotazů oddílů
PartitionQueryOperator
: LineTerminator? 'Take' LineTerminator? Expression
| LineTerminator? 'Take' 'While' LineTerminator? BooleanExpression
| LineTerminator? 'Skip' LineTerminator? Expression
| LineTerminator? 'Skip' 'While' LineTerminator? BooleanExpression
;
Operátor Take dotazu má za následek první n prvky kolekce. Při použití s modifikátorem WhileTake má operátor za následek první n prvky kolekce, které vyhovují logickému výrazu. Operátor Skip přeskočí první n prvky kolekce a vrátí zbytek kolekce. Při použití ve spojení s modifikátorem WhileSkip operátor přeskočí první n prvky kolekce, které vyhovují logickému výrazu, a vrátí zbytek kolekce. Výrazy v operátoru Take dotazu musí Skip být klasifikovány jako hodnota.
Take Operátor dotazu se podporuje jenom v případě, že typ kolekce obsahuje metodu:
Function Take(count As N) As CT
Skip Operátor dotazu se podporuje jenom v případě, že typ kolekce obsahuje metodu:
Function Skip(count As N) As CT
Take While Operátor dotazu se podporuje jenom v případě, že typ kolekce obsahuje metodu:
Function TakeWhile(predicate As Func(Of T, B)) As CT
Skip While Operátor dotazu se podporuje jenom v případě, že typ kolekce obsahuje metodu:
Function SkipWhile(predicate As Func(Of T, B)) As CT
Kód
Dim xs() As Integer = ...
Dim zs = From x In xs _
Skip 10 _
Take 5 _
Skip While x < 10 _
Take While x > 5 _
...
je obecně přeložen do
Dim xs() As Integer = ...
Dim zs = _
xs.Skip(10). _
Take(5). _
SkipWhile(Function(x) x < 10). _
TakeWhile(Function(x) x > 5)...
Poznámka.
Take a Skip nejsou vyhrazena slova.
Order By Query Operator
Operátor Order By dotazu objednává hodnoty, které se zobrazí v proměnných rozsahu.
OrderByQueryOperator
: LineTerminator? 'Order' 'By' LineTerminator? OrderExpressionList
;
OrderExpressionList
: OrderExpression ( Comma OrderExpression )*
;
OrderExpression
: Expression Ordering?
;
Ordering
: 'Ascending' | 'Descending'
;
Operátor Order By dotazu přebírá výrazy, které určují hodnoty klíče, které by se měly použít k seřazení proměnných iterace. Například následující dotaz vrátí produkty seřazené podle ceny:
Dim productsByPrice = _
From p In Products _
Order By p.Price _
Select p.Name
Řazení lze označit jako Ascending, v takovém případě menší hodnoty přicházejí před většími hodnotami, nebo Descendingv takovém případě větší hodnoty přicházejí před menší hodnoty. Výchozí hodnota pro řazení, pokud není zadán Ascendingžádný je . Následující dotaz například vrátí produkty seřazené podle ceny s nejnákladnějším produktem:
Dim productsByPriceDesc = _
From p In Products _
Order By p.Price Descending _
Select p.Name
Operátor Order By dotazu může zadat více výrazů pro řazení, v takovém případě je kolekce seřazena vnořeným způsobem. Například následující dotaz objedná zákazníky podle státu, pak podle města v rámci každého státu a pak podle PSČ v rámci každého města:
Dim customersByLocation = _
From c In Customers _
Order By c.State, c.City, c.ZIP _
Select c.Name, c.State, c.City, c.ZIP
Výrazy v operátoru Order By dotazu musí být klasifikovány jako hodnota. Operátor Order By dotazu je podporován pouze v případě, že typ kolekce obsahuje jednu nebo obě z následujících metod:
Function OrderBy(keySelector As Func(Of T, K)) As CT
Function OrderByDescending(keySelector As Func(Of T, K)) As CT
Návratový typ CT musí být seřazená kolekce. Seřazená kolekce je typ kolekce, který obsahuje jednu nebo obě metody:
Function ThenBy(keySelector As Func(Of T, K)) As CT
Function ThenByDescending(keySelector As Func(Of T, K)) As CT
Kód
Dim xs() As Integer = ...
Dim zs = From x In xs _
Order By x Ascending, x Mod 2 Descending _
...
je obecně přeložen do
Dim xs() As Integer = ...
Dim zs = _
xs.OrderBy(Function(x) x).ThenByDescending(Function(x) x Mod 2)...
Poznámka. Vzhledem k tomu, že operátory dotazu jednoduše mapují syntaxi na metody, které implementují konkrétní operaci dotazu, není zachování pořadí diktováno jazykem a je určeno implementací samotného operátoru. To se velmi podobá uživatelsky definovaným operátorům v tom, že implementace přetížení operátor sčítání pro uživatelem definovaný číselný typ nemusí provádět nic podobného sčítání. Samozřejmě, aby se zachovala předvídatelnost, implementace něčeho, co neodpovídá očekáváním uživatelů, se nedoporučuje.
Poznámka.
Order a By nejsou vyhrazena slova.
Seskupování podle operátoru dotazu
Operátor Group By dotazu seskupí proměnné rozsahu v oboru na základě jednoho nebo více výrazů a pak vytvoří nové proměnné rozsahu založené na těchto seskupeních.
GroupByQueryOperator
: LineTerminator? 'Group' ( LineTerminator? ExpressionRangeVariableDeclarationList )?
LineTerminator? 'By' LineTerminator? ExpressionRangeVariableDeclarationList
LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
;
Například následující dotaz seskupí všechny zákazníky podle Statea pak vypočítá počet a průměrný věk každé skupiny:
Dim averageAges = _
From cust In Customers _
Group By cust.State _
Into Count(), Average(cust.Age)
Operátor Group By dotazu má tři klauzule: volitelnou Group klauzuli, By klauzuli a klauzuli Into . Klauzule Group má stejnou syntaxi a účinek jako Select operátor dotazu, s tím rozdílem, že ovlivňuje pouze proměnné rozsahu dostupné v Into klauzuli, nikoli klauzuli By . Například:
Dim averageAges = _
From cust In Customers _
Group cust.Age By cust.State _
Into Count(), Average(Age)
Klauzule By deklaruje proměnné rozsahu výrazů, které se v operaci seskupení používají jako hodnoty klíče. Klauzule Into umožňuje deklaraci proměnných rozsahu výrazů, které počítají agregace nad jednotlivými skupinami vytvořenými By klauzulí.
Into V rámci klauzule lze proměnnou rozsahu výrazů přiřadit pouze výraz, což je volání metody agregační funkce. Agregační funkce je funkce typu kolekce skupiny (která nemusí být nutně stejným typem kolekce původní kolekce), která vypadá jako některé z následujících metod:
Function _name_() As _type_
Function _name_(selector As Func(Of T, R)) As R
Pokud agregační funkce přebírá argument delegáta, může mít výraz vyvolání výraz argumentu, který musí být klasifikován jako hodnota. Výraz argumentu může použít proměnné rozsahu, které jsou v oboru; v rámci volání agregační funkce tyto proměnné oblasti představují hodnoty ve skupině, nikoli všechny hodnoty v kolekci. Například v původním příkladu v této části Average funkce vypočítá průměr věku zákazníků podle státu, nikoli pro všechny zákazníky.
Všechny typy kolekcí se považují za agregační funkci Group definovanou v ní, která nepřijímá žádné parametry a jednoduše vrací skupinu. Mezi další standardní agregační funkce, které může poskytnout typ kolekce, patří:
Count a LongCount, které vrátí počet prvků ve skupině nebo počet prvků ve skupině, které vyhovují logickému výrazu.
Count a LongCount jsou podporovány pouze v případě, že typ kolekce obsahuje jednu z metod:
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, který vrátí součet výrazu napříč všemi prvky ve skupině.
Sum je podporován pouze v případě, že typ kolekce obsahuje jednu z metod:
Function Sum() As N
Function Sum(selector As Func(Of T, N)) As N
Min vrátí minimální hodnotu výrazu napříč všemi prvky ve skupině.
Min je podporován pouze v případě, že typ kolekce obsahuje jednu z metod:
Function Min() As N
Function Min(selector As Func(Of T, N)) As N
Max, který vrátí maximální hodnotu výrazu napříč všemi prvky ve skupině.
Max je podporován pouze v případě, že typ kolekce obsahuje jednu z metod:
Function Max() As N
Function Max(selector As Func(Of T, N)) As N
Average, který vrátí průměr výrazu napříč všemi prvky ve skupině.
Average je podporován pouze v případě, že typ kolekce obsahuje jednu z metod:
Function Average() As N
Function Average(selector As Func(Of T, N)) As N
Any, který určuje, zda skupina obsahuje členy, nebo pokud logický výraz je pravdivý pro libovolný prvek ve skupině.
Any vrátí hodnotu, kterou lze použít v logickém výrazu a je podporována pouze v případě, že typ kolekce obsahuje jednu z metod:
Function Any() As B
Function Any(predicate As Func(Of T, B)) As B
All, který určuje, zda logický výraz je pravdivý pro všechny prvky ve skupině.
All vrátí hodnotu, kterou lze použít v logickém výrazu a je podporována pouze v případě, že typ kolekce obsahuje metodu:
Function All(predicate As Func(Of T, B)) As B
Po operátoru Group By dotazu jsou proměnné rozsahu dříve v oboru skryté a proměnné rozsahu zavedené By klauzulí jsou Into k dispozici.
Group By Operátor dotazu je podporován pouze v případě, že typ kolekce obsahuje metodu:
Function GroupBy(keySelector As Func(Of T, K), _
resultSelector As Func(Of K, CT, R)) As CR
Deklarace proměnných rozsahu Group v klauzuli jsou podporovány pouze v případě, že typ kolekce obsahuje metodu:
Function GroupBy(keySelector As Func(Of T, K), _
elementSelector As Func(Of T, S), _
resultSelector As Func(Of K, CS, R)) As CR
Kód
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) _
...
je obecně přeložen do
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)})...
Poznámka:Group, Bya Into nejsou vyhrazena slova.
Agregační operátor dotazu
Operátor Aggregate dotazu provádí podobnou funkci jako Group By operátor, s výjimkou toho, že umožňuje agregaci nad skupinami, které již byly vytvořeny. Vzhledem k tomu, že skupina již byla vytvořena, klauzule Aggregate operátoru dotazu neskryje proměnné rozsahu v oboru (tímto způsobem Aggregate je spíše jako a LetGroup By a je více jako Select).Into
AggregateQueryOperator
: LineTerminator? 'Aggregate' LineTerminator? CollectionRangeVariableDeclaration QueryOperator*
LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
;
Následující dotaz například agreguje celkový součet všech objednávek zadaných zákazníky ve Washingtonu:
Dim orderTotals = _
From cust In Customers _
Where cust.State = "WA" _
Aggregate order In cust.Orders _
Into Sum(order.Total)
Výsledkem tohoto dotazu je kolekce, jejíž typ elementu je anonymní typ s vlastností pojmenovanou cust jako Customer a vlastnost s názvem Sum typed jako Integer.
Na rozdíl od Group By, další operátory dotazu lze umístit mezi Aggregate klauzule a Into klauzule.
Aggregate Mezi klauzulí a koncem Into klauzule lze použít všechny proměnné rozsahu v oboru, včetně proměnných deklarovaných klauzulíAggregate. Následující dotaz například agreguje součet všech objednávek zadaných zákazníky ve Washingtonu před 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)
Operátor Aggregate lze také použít ke spuštění výrazu dotazu. V tomto případě bude výsledkem výrazu dotazu jedna hodnota vypočítaná klauzulí Into . Následující dotaz například vypočítá součet všech součtů objednávek před 1. lednem 2006:
Dim ordersTotal = _
Aggregate order In Orders _
Where order.Date <= #01/01/2006# _
Into Sum(order.Total)
Výsledkem dotazu je jedna Integer hodnota. Operátor Aggregate dotazu je vždy k dispozici (i když musí být agregační funkce dostupná také pro platný výraz). Kód
Dim xs() As Integer = ...
Dim zs = _
Aggregate x In xs _
Where x < 5 _
Into Sum()
je obecně přeložen do
Dim xs() As Integer = ...
Dim zs = _
xs.Where(Function(x) x < 5).Sum()
Poznámka.
Aggregate a Into nejsou vyhrazena slova.
Operátor dotazu spojení skupiny
Operátor Group Join dotazu kombinuje funkce Join operátorů dotazu Group By do jednoho operátoru.
Group Join spojí dvě kolekce na základě odpovídajících klíčů extrahovaných z prvků a seskupí všechny prvky na pravé straně spojení, které odpovídají určitému prvku na levé straně spojení. Operátor tedy vytvoří sadu hierarchických výsledků.
GroupJoinQueryOperator
: LineTerminator? 'Group' 'Join' LineTerminator? CollectionRangeVariableDeclaration
JoinOrGroupJoinQueryOperator? LineTerminator? 'On' LineTerminator? JoinConditionList
LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
;
Následující dotaz například vytvoří prvky, které obsahují jméno jednoho zákazníka, skupinu všech objednávek a celkovou částku všech těchto objednávek:
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
Výsledkem dotazu je kolekce, jejíž typ elementu je anonymní typ se třemi vlastnostmi: Name, zadaný jako String, zadaný jako kolekce, Orders jejíž typ elementu je Order, a OrdersTotal, zadaný jako Integer.
Group Join Operátor dotazu je podporován pouze v případě, že typ kolekce obsahuje metodu:
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
Kód
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 _
...
je obecně přeložen do
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})...
Poznámka:Group, Joina Into nejsou vyhrazena slova.
Podmíněné výrazy
Podmíněný If výraz testuje výraz a vrací hodnotu.
ConditionalExpression
: 'If' OpenParenthesis BooleanExpression Comma Expression Comma Expression CloseParenthesis
| 'If' OpenParenthesis Expression Comma Expression CloseParenthesis
;
IIF Na rozdíl od funkce runtime však podmíněný výraz vyhodnocuje jeho operandy pouze v případě potřeby. Výraz tedy například nevyvolá výjimku, If(c Is Nothing, c.Name, "Unknown") pokud je Nothinghodnota c . Podmíněný výraz má dvě formy: jeden, který přebírá dva operandy a jeden, který přebírá tři operandy.
Pokud jsou k dispozici tři operandy, musí být všechny tři výrazy klasifikovány jako hodnoty a prvním operandem musí být logický výraz. Pokud je výsledek výrazu pravdivý, pak druhý výraz bude výsledkem operátoru, jinak třetí výraz bude výsledkem operátoru. Typ výsledku výrazu je dominantním typem mezi typy druhého a třetího výrazu. Pokud neexistuje dominantní typ, dojde k chybě v době kompilace.
Pokud jsou zadány dva operandy, musí být oba operandy klasifikovány jako hodnoty a první operand musí být buď odkazový typ, nebo typ hodnoty s možnou hodnotou null. Výraz If(x, y) se pak vyhodnotí jako výraz If(x IsNot Nothing, x, y), se dvěma výjimkami. První výraz je vyhodnocen pouze jednou a druhý, pokud je typ druhého operandu nenulový a typ první operand je, ? je odebrán z typu prvního operandu při určování dominantního typu pro typ výsledku výrazu. Například:
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
V obou formách výrazu, pokud je Nothingoperand , jeho typ se nepoužívá k určení dominantního typu. V případě výrazu If(<expression>, Nothing, Nothing)je dominantní typ považován za Object.
Literály XML – výrazy
Výraz literálu XML představuje hodnotu XML (eXtensible Markup Language) 1.0.
XMLLiteralExpression
: XMLDocument
| XMLElement
| XMLProcessingInstruction
| XMLComment
| XMLCDATASection
;
Výsledkem výrazu literálu XML je hodnota zadaná jako jeden z typů z System.Xml.Linq oboru názvů. Pokud typy v daném oboru názvů nejsou k dispozici, pak literál XML výraz způsobí chybu v době kompilace. Hodnoty se generují prostřednictvím volání konstruktoru přeloženého z výrazu literálu XML. Například kód:
Dim book As System.Xml.Linq.XElement = _
<book title="My book"></book>
přibližně odpovídá kódu:
Dim book As System.Xml.Linq.XElement = _
New System.Xml.Linq.XElement( _
"book", _
New System.Xml.Linq.XAttribute("title", "My book"))
Literální výraz XML může mít podobu dokumentu XML, elementu XML, instrukce pro zpracování XML, komentáře XML nebo oddílu CDATA.
Poznámka. Tato specifikace obsahuje pouze dostatek popisu XML pro popis chování jazyka Visual Basic. Další informace o jazyce XML naleznete na adrese http://www.w3.org/TR/REC-xml/.
Lexikální pravidla
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>'
;
Literální výrazy XML se interpretují pomocí lexikálních pravidel XML místo lexikálních pravidel regulárního kódu jazyka Visual Basic. Tyto dvě sady pravidel se obecně liší následujícími způsoby:
Prázdné znaky jsou ve formátu XML významné. Výsledkem je, že gramatika pro literální výrazy XML explicitně uvádí, kde je povolené prázdné znaky. Prázdné znaky se nezachovají, s výjimkou případů, kdy se vyskytuje v kontextu znakových dat v rámci elementu. Například:
' The following element preserves no whitespace Dim e1 = _ <customer> <name>Bob</> </> ' The following element preserves all of the whitespace Dim e2 = _ <customer> Bob </>Prázdné znaky konce řádku XML jsou normalizovány podle specifikace XML.
XML rozlišují malá a velká písmena. Klíčová slova se musí přesně shodovat s velikostí casingu nebo jinak dojde k chybě v době kompilace.
Ukončovací znaky čar jsou v JAZYCE XML považovány za prázdné znaky. V důsledku toho nejsou ve výrazech literálů XML potřeba žádné znaky pokračování řádku.
XML nepřijímá znaky s plnou šířkou. Pokud se použijí znaky s plnou šířkou, dojde k chybě v době kompilace.
Vložené výrazy
Literály XML můžou obsahovat vložené výrazy. Vložený výraz je výraz jazyka Visual Basic, který se vyhodnocuje a používá k vyplnění jedné nebo více hodnot v umístění vloženého výrazu.
XMLEmbeddedExpression
: '<' '%' '=' LineTerminator? Expression LineTerminator? '%' '>'
;
Například následující kód umístí řetězec John Smith jako hodnotu elementu XML:
Dim name as String = "John Smith"
Dim element As System.Xml.Linq.XElement = <customer><%= name %></customer>
Výrazy lze vložit do řady kontextů. Například následující kód vytvoří prvek s názvem customer:
Dim name As String = "customer"
Dim element As System.Xml.Linq.XElement = <<%= name %>>John Smith</>
Každý kontext, kde lze použít vložený výraz, určuje typy, které budou přijaty. V kontextu části výrazu vloženého výrazu platí normální lexikální pravidla pro kód jazyka Visual Basic, takže například musí být použita pokračování řádku:
' Visual Basic expression uses line continuation, XML does not
Dim element As System.Xml.Linq.XElement = _
<<%= name & _
name %>>John
Smith</>
Dokumenty XML
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
;
Výsledkem dokumentu XML je hodnota zadaná jako System.Xml.Linq.XDocument. Na rozdíl od specifikace XML 1.0 jsou dokumenty XML ve výrazech literálů XML nutné k určení prologue dokumentu XML; Literální výrazy XML bez prologue dokumentu XML jsou interpretovány jako jejich jednotlivá entita. Například:
Dim doc As System.Xml.Linq.XDocument = _
<?xml version="1.0"?>
<?instruction?>
<customer>Bob</>
Dim pi As System.Xml.Linq.XProcessingInstruction = _
<?instruction?>
Dokument XML může obsahovat vložený výraz, jehož typ může být libovolný typ; v době běhu však musí objekt splňovat požadavky konstruktoru XDocument nebo dojde k chybě za běhu.
Na rozdíl od regulárního XML výrazy dokumentu nepodporují DTD (deklarace typu dokumentu). Atribut kódování, pokud je zadán, bude ignorován, protože kódování literálu XML výraz je vždy stejné jako kódování samotného zdrojového souboru.
Poznámka. I když je atribut kódování ignorován, je stále platným atributem, aby se zachovala možnost zahrnout všechny platné dokumenty Xml 1.0 ve zdrojovém kódu.
Elementy XML
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+ ';'
;
Výsledkem elementu XML je hodnota zadaná jako System.Xml.Linq.XElement. Na rozdíl od běžného kódu XML mohou elementy XML vynechat název uzavírací značky a aktuální vnořený element bude uzavřen. Například:
Dim name = <name>Bob</>
Deklarace atributů v elementu XML vedou k hodnotám zadaným jako System.Xml.Linq.XAttribute. Hodnoty atributů jsou normalizovány podle specifikace XML. Pokud hodnota atributu je Nothing atribut nebude vytvořen, takže výraz hodnoty atributu nebude nutné kontrolovat Nothing. Například:
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 %>/>
Elementy a atributy XML mohou obsahovat vnořené výrazy na následujících místech:
Název elementu, v takovém případě vložený výraz musí být hodnota typu implicitně konvertibilní na System.Xml.Linq.XName. Například:
Dim name = <<%= "name" %>>Bob</>
Název atributu elementu, v takovém případě vložený výraz musí být hodnota typu implicitně konvertibilní na System.Xml.Linq.XName. Například:
Dim name = <name <%= "length" %>="3">Bob</>
Hodnota atributu prvku, v takovém případě vložený výraz může být hodnota libovolného typu. Například:
Dim name = <name length=<%= 3 %>>Bob</>
Atribut elementu, v takovém případě vložený výraz může být hodnota libovolného typu. Například:
Dim name = <name <%= new XAttribute("length", 3) %>>Bob</>
Obsah elementu, v takovém případě vložený výraz může být hodnota libovolného typu. Například:
Dim name = <name><%= "Bob" %></>
Pokud je Object()typ vloženého výrazu , pole bude předáno jako paramarray konstruktoru XElement .
Jmenné prostory XML
Elementy XML mohou obsahovat deklarace oboru názvů XML definované specifikacemi XML 1.0.
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
;
Omezení definování oborů názvů xml a xmlns vynucení a způsobí chyby v době kompilace. Deklarace oboru názvů XML nemohou mít vložený výraz pro jejich hodnotu; zadaná hodnota musí být neprázdný řetězcový literál. Například:
' 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</>
Poznámka. Tato specifikace obsahuje pouze dostatek popisu oboru názvů XML pro popis chování jazyka Visual Basic. Další informace o oborech názvů XML naleznete na adrese http://www.w3.org/TR/REC-xml-names/.
Názvy elementů a atributů XML lze kvalifikovat pomocí názvů oborů názvů. Obory názvů jsou vázané jako v běžném jazyce XML, s výjimkou, že všechny importy oborů názvů deklarované na úrovni souboru jsou považovány za deklarovány v kontextu ohraničující deklaraci, která je sama uzavřena všemi importy oboru názvů deklarovanými prostředím kompilace. Pokud nelze najít název oboru názvů, dojde k chybě v době kompilace. Například:
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
Obory názvů XML deklarované v elementu se nevztahují na literály XML uvnitř vložených výrazů. Například:
' Error: Namespace prefix 'db' is not declared
Dim customer = _
<db:customer xmlns:db="http://example.org/database">
<%= <db:customer>Bob</> %>
</>
Poznámka. Důvodem je, že vložený výraz může být cokoli, včetně volání funkce. Pokud volání funkce obsahovalo výraz xml literálu, není jasné, zda programátoři očekávají použití nebo ignorování oboru názvů XML.
Pokyny pro zpracování XML
Výsledkem instrukce zpracování XML je hodnota zadaná jako System.Xml.Linq.XProcessingInstruction. Pokyny pro zpracování XML nemohou obsahovat vložené výrazy, protože jsou platné syntaxe v rámci instrukce zpracování.
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 ">">'
;
Komentáře XML
Výsledkem komentáře XML je hodnota zadaná jako System.Xml.Linq.XComment. Komentáře XML nemohou obsahovat vložené výrazy, protože jsou v komentáři platné syntaxe.
XMLComment
: '<' '!' '-' '-' XMLCommentCharacter* '-' '-' '>'
;
XMLCommentCharacter
: '<Any XMLCharacter except dash (0x002D)>'
| '-' '<Any XMLCharacter except dash (0x002D)>'
;
Oddíly CDATA
Výsledkem oddílu CDATA je hodnota zadaná jako System.Xml.Linq.XCData. Oddíly CDATA nemohou obsahovat vložené výrazy, protože jsou platné syntaxe v oddílu CDATA.
XMLCDATASection
: '<' '!' ( 'CDATA' '[' XMLCDATASectionString? ']' )? '>'
;
XMLCDATASectionString
: '<Any XMLString that does not contain the string "]]>">'
;
Výrazy přístupu členů XML
Výraz přístupu člena XML přistupuje k členům hodnoty XML.
XMLMemberAccessExpression
: Expression '.' LineTerminator? '<' XMLQualifiedName '>'
| Expression '.' LineTerminator? '@' LineTerminator? '<' XMLQualifiedName '>'
| Expression '.' LineTerminator? '@' LineTerminator? IdentifierOrKeyword
| Expression '.' '.' '.' LineTerminator? '<' XMLQualifiedName '>'
;
Existují tři typy výrazů přístupu členů XML:
Přístup elementu, ve kterém název XML následuje za jedinou tečkou. Například:
Dim customer = _ <customer> <name>Bob</> </> Dim customerName = customer.<name>.ValuePřístup k elementu se mapuje na funkci:
Function Elements(name As System.Xml.Linq.XName) As _ System.Collections.Generic.IEnumerable(Of _ System.Xml.Linq.XNode)Výše uvedený příklad je tedy ekvivalentní:
Dim customerName = customer.Elements("name").ValuePřístup k atributu, ve kterém se identifikátor jazyka Visual Basic řídí tečkou a znakem at, nebo název XML se řídí tečkou a znakem at. Například:
Dim customer = <customer age="30"/> Dim customerAge = customer.@ageMapování přístupu k atributu na funkci:
Function AttributeValue(name As System.Xml.Linq.XName) as StringVýše uvedený příklad je tedy ekvivalentní:
Dim customerAge = customer.AttributeValue("age")Poznámka. Metoda
AttributeValuerozšíření (stejně jako související vlastnostValuerozšíření) není v současné době definována v žádném sestavení. Pokud jsou členy rozšíření potřeba, jsou automaticky definovány v sestavení, které se vytváří.Sestupné přístupy, ve kterých se názvy XML řídí třemi tečkami. Například:
Dim company = _ <company> <customers> <customer>Bob</> <customer>Mary</> <customer>Joe</> </> </> Dim customers = company...<customer>Descendents access maps to the function:
Function Descendents(name As System.Xml.Linq.XName) As _ System.Collections.Generic.IEnumerable(Of _ System.Xml.Linq.XElement)Výše uvedený příklad je tedy ekvivalentní:
Dim customers = company.Descendants("customer")
Základní výraz výrazu přístupu člena XML musí být hodnota a musí být typu:
Pokud je prvek nebo sestupný přístup,
System.Xml.Linq.XContainerodvozený typ neboSystem.Collections.Generic.IEnumerable(Of T)odvozený typ, kdeTjeSystem.Xml.Linq.XContainernebo odvozený typ.Pokud přístup k atributu nebo
System.Xml.Linq.XElementodvozený typ neboSystem.Collections.Generic.IEnumerable(Of T)odvozený typ, kdeTjeSystem.Xml.Linq.XElementnebo odvozený typ.
Názvy ve výrazech přístupu členů XML nemohou být prázdné. Mohou být kvalifikovaným oborem názvů pomocí libovolných oborů názvů definovaných importem. Například:
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
Prázdné znaky nejsou povoleny za tečkami ve výrazu přístupu člena XML nebo mezi úhlovými závorkami a názvem. Například:
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 >
Pokud typy v System.Xml.Linq oboru názvů nejsou k dispozici, pak výraz přístupu člena XML způsobí chybu v době kompilace.
Operátor Await
Operátor await souvisí s asynchronními metodami, které jsou popsány v části Async Methods.
AwaitOperatorExpression
: 'Await' Expression
;
Await je vyhrazené slovo, pokud bezprostředně uzavřená metoda nebo výraz lambda, ve kterém se zobrazí, má Async modifikátor, a pokud Await se zobrazí za tímto Async modifikátorem; není rezervován jinde. Není také rezervován v direktivách preprocesoru. Operátor await je povolen pouze v těle metody nebo výrazy lambda, kde se jedná o rezervované slovo. V rámci bezprostředně uzavřené metody nebo lambda nemusí výraz await nastat uvnitř těla Catch nebo Finally bloku, ani uvnitř textu SyncLock příkazu, ani uvnitř výrazu dotazu.
Operátor await přebírá jeden výraz, který musí být klasifikován jako hodnota a jehož typ musí být očekávaným typem, nebo Object. Pokud je Object jeho typ, veškeré zpracování je odloženo do doby běhu.
C Typ je očekáván, pokud jsou splněny všechny následující podmínky:
Cobsahuje přístupnou instanci nebo metodu rozšíření s názvemGetAwaiter, která nemá žádné argumenty a která vrací určitý typE;Eobsahuje čitelný instanci nebo vlastnost rozšíření s názvemIsCompleted, která nepřijímá žádné argumenty a má typ Boolean;Eobsahuje přístupnou instanci nebo metodu rozšíření s názvemGetResult, která nepřijímá žádné argumenty;Eimplementuje buďSystem.Runtime.CompilerServices.INotifyCompletionneboICriticalNotifyCompletion.
Pokud GetResult byl Subvýraz await, je klasifikován jako void. V opačném případě je výraz await klasifikován jako hodnota a jeho typ je návratový GetResult typ metody.
Tady je příklad třídy, kterou lze očekávat:
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
Poznámka. Autoři knihoven se doporučuje postupovat podle vzoru, podle kterého volají delegáta pokračování na stejném SynchronizationContext místě jako OnCompleted oni sami. Delegování obnovení by se také nemělo provádět synchronně v rámci OnCompleted metody, protože to může vést k přetečení zásobníku: místo toho by měl být delegát zařazen do fronty pro následné spuštění.
Když tok řízení dosáhne operátoru Await , chování je následující.
Metoda
GetAwaiteroperandu await je vyvolána. Výsledkem tohoto vyvolání je operátor awaiter.Vlastnost awaiteru
IsCompletedse načte. Pokud je výsledek pravdivý, postupujte takto:- Metoda
GetResultawaiter je vyvolána. PokudGetResultbyla funkce, pak hodnota výrazu await je návratová hodnota této funkce.
- Metoda
Pokud isCompleted vlastnost není true, pak:
Buď
ICriticalNotifyCompletion.UnsafeOnCompletedje vyvolána na operátoru await (pokud typEawaiter implementujeICriticalNotifyCompletion) neboINotifyCompletion.OnCompleted(jinak). V obou případech předá delegáta obnovení přidruženého k aktuální instanci asynchronní metody.Řídicí bod aktuální instance asynchronní metody je pozastavený a tok řízení se obnoví v aktuálním volajícím (definovaném v metodách Async oddílu).
Pokud se později vyvolá delegát obnovení,
- delegát obnovení nejprve obnoví
System.Threading.Thread.CurrentThread.ExecutionContextto, co bylo v doběOnCompleted, kdy byl volána, - pak obnoví tok řízení v řídicím bodě instance asynchronní metody (viz část Asynchronní metody),
- kde volá
GetResultmetodu awaiter, jak je uvedeno v 2.1 výše.
- delegát obnovení nejprve obnoví
Pokud má operand await typ Object, je toto chování odloženo do modulu runtime:
- Krok 1 se provádí voláním getAwaiter() bez argumentů; proto může svázat za běhu s metodami instance, které berou volitelné parametry.
- Krok 2 se provádí načtením vlastnosti IsCompleted() bez argumentů a pokusem o vnitřní převod na logickou hodnotu.
- Krok 3.a je dosaženo pokusem
TryCast(awaiter, ICriticalNotifyCompletion), a pokud se to nezdaří pakDirectCast(awaiter, INotifyCompletion).
Delegát obnovení předaný ve verzi 3.a může být vyvolán pouze jednou. Pokud je vyvolána více než jednou, chování není definováno.
Visual Basic language spec