Výrazy v jazyce Visual Basic

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, AddHandlera RemoveHandler pří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 jako f() a f(Of Integer) interpretován jako f(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 Module
    
  • Metodu 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:

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

    2. Pokud je System.Linq.Expressions.Expression(Of T)cílový typ a T je typem delegáta, pak je metoda lambda interpretována, jako by byla použita ve výrazu delegate-construction pro T a 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 Sub lambda 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říklad New 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; Object v 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 Module
    
  • Skupinu 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 jako f()).

  • 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 Get objektu 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:

    1. 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)nebo IEnumerable(Of T), a literál pole má jednu úroveň vnoření, pak je literál pole přetříděn jako hodnota typu T().

    2. 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, Object použ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 } odvozeno Object() jako typ a jazyka verze 9.0 a Integer() 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 Nothing lze 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 typu Object.

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 String tohoto pravidla jsou výjimkou a jsou povoleny pouze u hodnot null, protože String př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 +a Not- 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.Chr pokud je konstantní hodnota mezi 0 a 128; Microsoft.VisualBasic.Strings.AscW pokud konstantní řetězec není prázdný; Microsoft.VisualBasic.Strings.Asc pokud konstantní řetězec není prázdný.

Následující konstrukce nejsou povoleny ve výrazech konstant:

  • Implicitní vazba prostřednictvím With kontextu

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

  1. 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 Get přístupová proměnná, která vrací místní proměnnou a výraz je součástí vyvolání výrazu, příkazu vyvolání nebo AddressOf vý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í.

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

    1. 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.
    2. 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), kde E je identifikátor a A je seznam argumentů typu, pokud existuje.
    3. V opačném případě je výsledek úplně stejný jako přístup člena formuláře T.E(Of A), kde T je typ obsahující odpovídající člen, E je identifikátor a A je seznam argumentů typu, pokud existuje. V tomto případě se jedná o chybu, která identifikátor odkazuje na nesdílený člen.
  3. 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:

    1. 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.
    2. 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ů.
    3. 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), kde M je standardní modul obsahující odpovídající člen, E je identifikátor a A je 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.
  4. 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.

  5. Pokud zdrojový soubor obsahující odkaz na název obsahuje jeden nebo více importů:

    1. 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.
    2. 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.
    3. 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), kde M je standardní modul obsahující odpovídající člen, E je identifikátor a A je 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.
  6. 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.

  7. Pokud prostředí kompilace definuje jeden nebo více importů:

    1. 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.
    2. 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.
    3. 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), kde M je standardní modul obsahující odpovídající člen, E je identifikátor a A je 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.
  8. 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 GetType výrazu vrátit System.Type objekt, 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:

  1. Pokud E je vynechán, výraz z bezprostředně obsahujícího With příkazu se nahradí E a provede se přístup člena. Pokud neexistuje žádný příkaz obsahující With , dojde k chybě v době kompilace.

  2. Pokud E je klasifikovaný jako obor názvů nebo E je klíčovým slovem Global, provede se vyhledávání členů v kontextu zadaného oboru názvů. Pokud I je 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.

  3. Pokud E je typ nebo výraz klasifikovaný jako typ, provede se vyhledávání členů v kontextu zadaného typu. Pokud I je název přístupného člena E, pak E.I se vyhodnotí a klasifikuje takto:

    1. Pokud I je klíčové slovo New a E není výčtem, dojde k chybě v době kompilace.
    2. Pokud I identifikuje typ se stejným počtem parametrů typu, jako byl zadán v seznamu argumentů typu, pokud existuje, výsledek je tento typ.
    3. Pokud I identifikuje 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.
    4. Pokud I identifikuje 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.
    5. Pokud I identifikuje 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é I v E. V opačném případě je výsledkem sdílená proměnná I v Esouboru .
    6. Pokud I identifikuje 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.
    7. Pokud I identifikuje konstantu a nebyl zadán žádný seznam argumentů typu, je výsledkem hodnota této konstanty.
    8. Pokud I identifikuje člen výčtu a nebyl zadán žádný seznam argumentů typu, je výsledkem hodnota tohoto člena výčtu.
    9. V opačném případě je E.I neplatným odkazem na člena a dojde k chybě v době kompilace.
  4. Je-li E klasifikována jako proměnná nebo hodnota, typ, který je T, pak se členské vyhledávání provádí v kontextu T. Pokud I je název přístupného člena T, pak E.I se vyhodnotí a klasifikuje takto:

    1. Pokud I je klíčové slovo New, je Me, MyBaseE nebo MyClass, a nebyly zadány žádné argumenty typu, pak výsledek je skupina metod představující konstruktory instance typu E s přidruženým cílovým výrazem E a žádný seznam argumentů typu. V opačném případě dojde k chybě kompilace.
    2. Pokud I identifikuje jednu nebo více metod, včetně rozšiřujících metod, pokud T není Object, je výsledkem skupina metod se seznamem argumentů přidruženého typu a přidruženým cílovým výrazem E.
    3. Pokud I identifikuje 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ýrazem E.
    4. Pokud I identifikuje 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é I v objektu, na který Eodkazuje . Pokud T je typ odkazu, je výsledkem proměnná I v objektu, na který Eodkazuje . V opačném případě je-li T typ hodnoty a výraz E je klasifikován jako proměnná, výsledek je proměnná, jinak je výsledkem hodnota.
    5. Pokud I identifikuje 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ýrazem E.
    6. Pokud I identifikuje konstantu a nebyly zadány žádné argumenty typu, je výsledkem hodnota této konstanty.
    7. Pokud I identifikuje člen výčtu a nebyly zadány žádné argumenty typu, je výsledkem hodnota tohoto člena výčtu.
    8. Pokud T je Object, 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ýrazem E.
  5. V opačném případě je E.I neplatný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:

  • TypeToCollect Parametr 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.

  • CreateInstanceMethodName Parametr určuje metodu volání ve třídě skupiny pro vytvoření nové instance ve výchozí vlastnosti instance.

  • DisposeInstanceMethodName Parametr 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 hodnotu Nothing.

  • DefaultInstanceAlias Parametr 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 je Nothing tento 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 jazyka DefaultInstanceAlias Visual 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:

  1. Nejprve se zkontroluje každý vnořený typ obsahující výraz, počínaje od nejvnitřnějšího a od nejkrajnějšího.
  2. 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ů.
  3. Importy ve zdrojovém souboru se pak zkontrolují.
  4. 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, Objectnebo System.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.IndexOutOfRangeException vyvolá se výjimka. Každý výraz musí být implicitně konvertibilní na typ Integer. 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á Get pří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 Object nebo System.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ý jako Object. 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.AmbiguousMatchException vyvolá 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ýsledkem Nothing.

  • 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.MissingMemberException je 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:

  • M není Partial nebo má tělo.

  • Obě M a D jsou funkce, nebo D je podprogram.

  • M a D mají stejný počet parametrů.

  • Typy parametrů M každého mají převod z typu odpovídajícího typu parametru Da 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 M má rozšiřující převod na odpovídající typ parametru D.

  • Nebo návratový typ, pokud existuje, M má 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 L obsahuje parametry, D má stejný počet parametrů. (Pokud L nemá žádné parametry, parametry D budou ignorovány.)

  • Typy parametrů L každého mají převod na typ odpovídajícího typu parametru Da jejich modifikátory (tj. ByRef, ByVal), které odpovídají.

  • Pokud D je funkce, návratový L typ má převod na návratový Dtyp . (Pokud D je podprogram, je vrácená hodnota L ignorová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 x názvu odvodí název x.

  • Výraz x.y přístupu člena odvodí název y.

  • Vyhledávací výraz x!y slovníku odvodí název y.

  • Vyvolání nebo výraz indexu bez argumentů x() odvodí název x.

  • Výraz x.<y>přístupu člena XML , x...<y>x.@y odvodí název y.

  • Výraz přístupu člena XML, který je cílem výrazu x.<y>.z přístupu člena, odvodí název z.

  • Výraz přístupu člena XML, který je cílem vyvolání nebo výraz indexu bez argumentů x.<y>.z() odvodí název z.

  • Výraz přístupu člena XML, který je cílem vyvolání nebo výraz x.<y>(0) indexu odvodí název y.

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:

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

  2. 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 , Nota Andmohou Or bý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, ULong a Long. Pokud je zapnutá kontrola přetečení celého čísla a součet je mimo rozsah typu výsledku, System.OverflowException vyvolá 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.

  • Single a Double. Součet se vypočítá podle pravidel aritmetik IEEE 754.

  • Decimal. Pokud je výsledná hodnota příliš velká pro reprezentaci v desítkovém System.OverflowException formá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. Oba String operandy jsou zřetězeny dohromady.

  • Date. Typ System.DateTime definuje přetížené operátory sčítání. Vzhledem k tomu System.DateTime , že je ekvivalentem vnitřního Date typu, jsou tyto operátory k dispozici také pro Date tento 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, ULong a Long. Pokud je zapnutá kontrola přetečení celého čísla a rozdíl je mimo rozsah typu výsledku, System.OverflowException vyvolá 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.

  • Single a Double. Rozdíl se vypočítá podle pravidel aritmetik IEEE 754.

  • Decimal. Pokud je výsledná hodnota příliš velká pro reprezentaci v desítkovém System.OverflowException formá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. Typ System.DateTime definuje přetížené operátory odčítání. Vzhledem k tomu System.DateTime , že je ekvivalentem vnitřního Date typu, jsou tyto operátory k dispozici také pro Date tento 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, ULong a Long. Pokud je kontrola přetečení celého čísla zapnutá a produkt je mimo rozsah typu výsledku, System.OverflowException vyvolá 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.

  • Single a Double. Produkt se vypočítá podle pravidel aritmetik IEEE 754.

  • Decimal. Pokud je výsledná hodnota příliš velká pro reprezentaci v desítkovém System.OverflowException formá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:

  • Single a Double. Podíl se vypočítá podle pravidel aritmetik IEEE 754.

  • Decimal. Pokud je hodnota pravého operandu nula, vyvolá System.DivideByZeroException se výjimka. Pokud je výsledná hodnota příliš velká pro reprezentaci v desítkovém System.OverflowException formá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, ULongIntegera Long. Výsledkem x Mod y je hodnota vytvořená x - (x \ y) * y. Pokud y je nula, System.DivideByZeroException vyvolá se výjimka. Operátor modulo nikdy nezpůsobí přetečení.

  • Single a Double. Zbytek se vypočítá podle pravidel aritmetik IEEE 754.

  • Decimal. Pokud je hodnota pravého operandu nula, vyvolá System.DivideByZeroException se výjimka. Pokud je výsledná hodnota příliš velká pro reprezentaci v desítkovém System.OverflowException formá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ů. True je považován za menší než False, který odpovídá jejich číselným hodnotám.

  • Byte, SByte, UShort, Short, UInteger, Integer, ULong a Long. Operátory porovnávají číselné hodnoty dvou integrálních operandů.

  • Single a Double. 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říkazem Option 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:

  • Boolean Typ:

    • Logická And operace se provádí na svých dvou operandech.

    • Na svém operandu se provádí logická Not operace.

    • Logická Or operace se provádí na svých dvou operandech.

    • Logická exkluzivníOr operace 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á 1 Xor 0 = 1, 1 Xor 1 = 0).

  • Pokud logické operátory And a Or jsou pro typ Boolean?zvednuty , jsou rozšířeny tak, aby zahrnovaly logickou logiku se třemi hodnotami, například:

    • And vyhodnotí hodnotu true, pokud jsou oba operandy pravdivé; false pokud jeden z operandů je false; Nothing jinak.

    • Or vyhodnotí hodnotu true, pokud je jeden operand pravdivý; False je oba operandy false; Nothing jinak.

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 AndAlso vyhodnotí False jako nebo vrátí hodnotu True z operátoru IsFalse , 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á And operace.

  • Pokud se první operand operace OrElse vyhodnotí True jako nebo vrátí hodnotu True z operátoru IsTrue , vrátí výraz první operand. V opačném případě se vyhodnotí druhý operand a logická Or operace 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:

  • T je Boolean nebo Boolean?

  • T má rozšiřující převod na Boolean

  • T má rozšiřující převod na Boolean?

  • T definuje dva pseudo operátory a IsTrueIsFalse.

  • T má zužující převod na Boolean? , který nezahrnuje převod z Boolean na Boolean?.

  • T má zužující převod na Boolean.

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 Return příkazech v bloku příkazu.

  • V asynchronním výrazu lambda je Task(Of T) návratový typ, kde T je dominantním typem výrazů ve všech Return příkazech v bloku příkazu.

  • Ve výrazu lambda iterátoru je IEnumerable(Of T) návratový typ tam, kde T je dominantním typem výrazů ve všech Yield pří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 Error a Resume příkazy nejsou povoleny, i když Try jsou 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 typ Me není 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 Func za předpokladu, že má stejný podpis, včetně návratového typu, jako odpovídající Func typ.

  • System.Linq.Expressions.Expression(Of D) Typ lze použít místo typu delegáta Func za předpokladu, že D je to typ delegáta, který má stejný podpis, včetně návratového typu, jako typ shodyFunc.

  • Typ T př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 S představuje typ prvku druhé vstupní kolekce v případě operátorů dotazu, které provádějí spojení.

  • Typ K představuje typ klíče v případě operátorů dotazu, které mají sadu proměnných rozsahu, které fungují jako klíče.

  • Typ N př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).

  • B Typ představuje typ, který lze použít v logickém výrazu.

  • Typ R představuje typ prvku kolekce výsledků, pokud operátor dotazu vytvoří kolekci výsledků. R zá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á R se o typ této proměnné rozsahu. V příkladu

    Dim custNames = From c In Customers
                    Select c.Name
    

    výsledkem dotazu bude typ kolekce s typem Stringprvku . Pokud je v oboru více proměnných rozsahu, je anonymní R typ, který obsahuje všechny proměnné rozsahu v oboru jako Key pole. V příkladu:

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

    Výsledkem dotazu bude typ kolekce s typem elementu anonymního typu s vlastností jen pro čtení s názvem Name typu String a vlastností jen pro čtení s názvem ProductName typu String.

    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 c a o mohly být přístupné bez kvalifikace v operátoru Select dotazu, i když typ elementu vstupní kolekce byl anonymní typ.

  • CX Typ představuje typ kolekce, ne nutně vstupní typ kolekce, jehož typ prvku je nějaký typ X.

Typ dotazovatelné kolekce musí splňovat jednu z následujících podmínek v pořadí podle preference:

  • Musí definovat odpovídající Select metodu.

  • Musí mít jednu z následujících metod.

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

    které lze volat k získání dotazovatelné kolekce. Pokud jsou k dispozici obě metody, AsQueryable je vhodnější než AsEnumerable.

  • Musí mít metodu.

    Function Cast(Of T)() As CT
    

    které 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>.Value
    

    Pří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").Value
    
  • Pří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.@age
    

    Mapování přístupu k atributu na funkci:

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

    Výše uvedený příklad je tedy ekvivalentní:

    Dim customerAge = customer.AttributeValue("age")
    

    Poznámka. Metoda AttributeValue rozšíření (stejně jako související vlastnost Valuerozšíř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.XContainer odvozený typ nebo System.Collections.Generic.IEnumerable(Of T) odvozený typ, kde T je System.Xml.Linq.XContainer nebo odvozený typ.

  • Pokud přístup k atributu nebo System.Xml.Linq.XElement odvozený typ nebo System.Collections.Generic.IEnumerable(Of T) odvozený typ, kde T je System.Xml.Linq.XElement nebo 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:

  • C obsahuje přístupnou instanci nebo metodu rozšíření s názvem GetAwaiter , která nemá žádné argumenty a která vrací určitý typ E;

  • E obsahuje čitelný instanci nebo vlastnost rozšíření s názvem IsCompleted , která nepřijímá žádné argumenty a má typ Boolean;

  • E obsahuje přístupnou instanci nebo metodu rozšíření s názvem GetResult , která nepřijímá žádné argumenty;

  • E implementuje buď System.Runtime.CompilerServices.INotifyCompletion nebo ICriticalNotifyCompletion.

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

  1. Metoda GetAwaiter operandu await je vyvolána. Výsledkem tohoto vyvolání je operátor awaiter.

  2. Vlastnost awaiteru IsCompleted se načte. Pokud je výsledek pravdivý, postupujte takto:

    1. Metoda GetResult awaiter je vyvolána. Pokud GetResult byla funkce, pak hodnota výrazu await je návratová hodnota této funkce.
  3. Pokud isCompleted vlastnost není true, pak:

    1. Buď ICriticalNotifyCompletion.UnsafeOnCompleted je vyvolána na operátoru await (pokud typ E awaiter implementuje ICriticalNotifyCompletion) nebo INotifyCompletion.OnCompleted (jinak). V obou případech předá delegáta obnovení přidruženého k aktuální instanci asynchronní metody.

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

    3. Pokud se později vyvolá delegát obnovení,

      1. delegát obnovení nejprve obnoví System.Threading.Thread.CurrentThread.ExecutionContext to, co bylo v době OnCompleted , kdy byl volána,
      2. pak obnoví tok řízení v řídicím bodě instance asynchronní metody (viz část Asynchronní metody),
      3. kde volá GetResult metodu awaiter, jak je uvedeno v 2.1 výše.

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ří pak DirectCast(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.