Zdrojové soubory a obory názvů

Program jazyka Visual Basic se skládá z jednoho nebo více zdrojových souborů. Při kompilaci programu se všechny zdrojové soubory zpracovávají společně; zdrojových souborů tak může záviset na sobě, pravděpodobně cyklický, bez jakéhokoli požadavku na předání deklarace. Textové pořadí deklarací v textu programu je obecně bez významnosti.

Zdrojový soubor se skládá z volitelné sady příkazů možností, příkazů importu a atributů, za kterými následuje tělo oboru názvů. Atributy, které musí mít buď Assembly modifikátor, Module se vztahují na sestavení nebo modul .NET vytvořené kompilací. Tělo zdrojového souboru funguje jako implicitní deklarace oboru názvů pro globální obor názvů, což znamená, že všechny deklarace na nejvyšší úrovni zdrojového souboru jsou umístěny do globálního oboru názvů. Například:

FileA.vb:

Class A
End Class

FileB.vb:

Class B
End Class

Dva zdrojové soubory přispívají do globálního oboru názvů, v tomto případě deklarují dvě třídy s plně kvalifikovanými názvy A a B. Vzhledem k tomu, že dva zdrojové soubory přispívají ke stejnému prostoru deklarace, byla by chyba, pokud by každá obsahovala deklaraci člena se stejným názvem.

Poznámka. Prostředí kompilace může přepsat deklarace oboru názvů, do kterých je zdrojový soubor implicitně umístěn.

S výjimkou případů, kdy je uvedeno, mohou být příkazy v programu jazyka Visual Basic ukončeny buď ukončovacím znakem řádku, nebo dvojtečka.

Start
    : OptionStatement* ImportsStatement* AttributesStatement* NamespaceMemberDeclaration*
    ;

StatementTerminator
    : LineTerminator
    | ':'
    ;

AttributesStatement
    : Attributes StatementTerminator
    ;

Spuštění a ukončení programu

Spuštění programu nastane, když spouštěcí prostředí spustí určenou metodu, která se označuje jako vstupní bod programu. Tato metoda vstupního bodu, která musí být vždy pojmenována Main, musí být sdílena, nemůže být obsažena v obecném typu, nemůže mít modifikátor async a musí mít jeden z následujících podpisů:

Sub Main()
Sub Main(args() As String)
Function Main() As Integer
Function Main(args() As String) As Integer

Přístupnost metody vstupního bodu není relevantní. Pokud program obsahuje více než jeden vhodný vstupní bod, musí prostředí kompilace určit jeden jako vstupní bod. V opačném případě dojde k chybě kompilace. Prostředí kompilace může také vytvořit metodu vstupního bodu, pokud neexistuje.

Když program začne, pokud vstupní bod má parametr, argument zadaný spouštěcím prostředím obsahuje argumenty příkazového řádku programu reprezentované jako řetězce. Pokud vstupní bod má návratový Integertyp , vrátí se hodnota vrácená z funkce do spouštěcího prostředí jako výsledek programu.

Ve všech ostatních ohledech se metody vstupních bodů chovají stejným způsobem jako jiné metody. Když provádění opustí vyvolání metody vstupního bodu vytvořené spouštěcím prostředím, program se ukončí.

Možnosti kompilace

Zdrojový soubor může zadat možnosti kompilace ve zdrojovém kódu pomocí příkazů option.

OptionStatement
    : OptionExplicitStatement
    | OptionStrictStatement
    | OptionCompareStatement
    | OptionInferStatement
    ;

Příkaz Option se vztahuje pouze na zdrojový soubor, ve kterém se zobrazí, a ve zdrojovém souboru se může objevit pouze jeden z každého typu Option příkazu. Například:

Option Strict On
Option Compare Text
Option Strict Off    ' Not allowed, Option Strict is already specified.
Option Compare Text  ' Not allowed, Option Compare is already specified.

Existují čtyři možnosti kompilace: striktní sémantika typu, explicitní sémantika deklarace, sémantika porovnání a sémantika místního typu proměnné. Pokud zdrojový soubor neobsahuje konkrétní Option příkaz, pak prostředí kompilace určuje, která konkrétní sada sémantiky bude použita. K dispozici je také pátá možnost kompilace, celočíselná kontrola přetečení, která lze zadat pouze prostřednictvím prostředí kompilace.

Příkaz Option Explicit

Příkaz Option Explicit určuje, zda mohou být místní proměnné implicitně deklarovány. Klíčová slova nebo Off mohou následovat za příkazemOn; pokud není zadána ani jedna, výchozí hodnota je On. Pokud v souboru není zadán žádný příkaz, prostředí kompilace určuje, které bude použito.

OptionExplicitStatement
    : 'Option' 'Explicit' OnOff? StatementTerminator
    ;

OnOff
    : 'On' | 'Off'
    ;

Poznámka. Explicit a Off nejsou vyhrazena slova.

Option Explicit Off

Module Test
    Sub Main()
        x = 5 ' Valid because Option Explicit is off.
    End Sub
End Module

V tomto příkladu je místní proměnná x implicitně deklarována přiřazením. Typ x je Object.

Option Strict – příkaz

Příkaz Option Strict určuje, zda převody a operace Object jsou řízeny striktní nebo permissivní sémantikou typu a zda typy jsou implicitně zadány, jako Object by nebyla zadána žádná As klauzule. Za příkazem mohou následovat klíčová slova On , nebo Offpokud není zadána žádná, výchozí hodnota je On. Pokud v souboru není zadán žádný příkaz, prostředí kompilace určuje, které bude použito.

OptionStrictStatement
    : 'Option' 'Strict' OnOff? StatementTerminator
    ;

Poznámka. Strict a Off nejsou vyhrazena slova.

Option Strict On

Module Test
    Sub Main()
        Dim x ' Error, no type specified.
        Dim o As Object
        Dim b As Byte = o ' Error, narrowing conversion.

        o.F() ' Error, late binding disallowed.
        o = o + 1 ' Error, addition is not defined on Object.
    End Sub
End Module

V rámci přísné sémantiky jsou zakázány následující:

  • Zužování převodů bez explicitního operátoru přetypování

  • Opožděná vazba.

  • Operace s jiným typem Object než TypeOf...Is, Isa IsNot.

  • Vynechání As klauzule v deklaraci, která nemá odvozený typ.

Option Compare – příkaz

Příkaz Option Compare určuje sémantiku porovnání řetězců. Porovnávání řetězců se provádí buď pomocí binárních porovnání (ve kterých se porovnává binární hodnota Unicode každého znaku) nebo porovnání textu (ve kterém se porovnává lexikální význam každého znaku pomocí aktuální jazykové verze). Pokud v souboru není zadán žádný příkaz, prostředí kompilace určuje, jaký typ porovnání se použije.

OptionCompareStatement
    : 'Option' 'Compare' CompareOption StatementTerminator
    ;

CompareOption
    : 'Binary' | 'Text'
    ;

Poznámka:Compare, Binarya Text nejsou vyhrazena slova.

Option Compare Text

Module Test
    Sub Main()
        Console.WriteLine("a" = "A")    ' Prints True.
    End Sub
End Module

V tomto případě se porovnání řetězců provádí pomocí porovnání textu, které ignoruje rozdíly mezi písmeny. Pokud Option Compare Binary by bylo zadáno, bylo by to vytištěno False.

Kontroly přetečení celého čísla

Celočíselné operace je možné zkontrolovat nebo nekontrolovat podmínky přetečení za běhu. Pokud jsou zaškrtnuté podmínky přetečení a přeteče celočíselná operace, System.OverflowException vyvolá se výjimka. Pokud nejsou podmínky přetečení zaškrtnuté, celočíselná operace přetečení nevyvolá výjimku. Prostředí kompilace určuje, jestli je tato možnost zapnutá nebo vypnutá.

Option Infer – příkaz

Příkaz Option Infer určuje, zda deklarace místních proměnných, které nemají žádnou As klauzuli odvozený typ nebo použít Object. Za příkazem mohou následovat klíčová slova On , nebo Offpokud není zadána žádná, výchozí hodnota je On. Pokud v souboru není zadán žádný příkaz, prostředí kompilace určuje, které bude použito.

OptionInferStatement
    : 'Option' 'Infer' OnOff? StatementTerminator
    ;

Poznámka. Infer a Off nejsou vyhrazena slova.

Option Infer On

Module Test
    Sub Main()
        ' The type of x is Integer
        Dim x = 10

        ' The type of y is String
        Dim y = "abc"
    End Sub
End Module

Příkaz Imports

Imports příkazy importují názvy entit do zdrojového souboru, což umožňuje odkazovat na názvy bez kvalifikace nebo importovat obor názvů pro použití ve výrazech XML.

ImportsStatement
    : 'Imports' ImportsClauses StatementTerminator
    ;

ImportsClauses
    : ImportsClause ( Comma ImportsClause )*
    ;

ImportsClause
    : AliasImportsClause
    | MembersImportsClause
    | XMLNamespaceImportsClause
    ;

V rámci deklarací členů ve zdrojovém souboru, který obsahuje Imports příkaz, lze na typy obsažené v daném oboru názvů odkazovat přímo, jak je vidět v následujícím příkladu:

Imports N1.N2

Namespace N1.N2
    Class A
    End Class
End Namespace 

Namespace N3
    Class B
        Inherits A
    End Class
End Namespace

Zde v rámci zdrojového souboru jsou členy typu oboru názvů N1.N2 přímo k dispozici, a proto třída N3.B je odvozena od třídy N1.N2.A.

Imports příkazy musí být uvedeny za libovolnými Option příkazy, ale před deklaracemi typu. Prostředí kompilace může také definovat implicitní Imports příkazy.

Imports příkazy zpřístupňují názvy ve zdrojovém souboru, ale nehlásí nic v prostoru deklarace globálního oboru názvů. Rozsah názvů importovaných příkazem Imports přesahuje deklarace členů oboru názvů obsažené ve zdrojovém souboru. Rozsah Imports příkazu výslovně neobsahuje další Imports příkazy ani neobsahuje jiné zdrojové soubory. Imports příkazy se nemusí vzájemně odkazovat.

V tomto příkladu je poslední Imports příkaz chybný, protože není ovlivněn prvním aliasem importu.

Imports R1 = N1 ' OK.
Imports R2 = N1.N2 ' OK.
Imports R3 = R1.N2 ' Error: Can't refer to R1.

Namespace N1.N2
End Namespace

Poznámka. Názvy oborů názvů nebo typů, které se zobrazují v Imports příkazech, se vždy považují za plně kvalifikované. To znamená, že identifikátor úplně vlevo v oboru názvů nebo názvu typu se vždy překládá v globálním oboru názvů a zbytek překladu pokračuje podle normálních pravidel překladu názvů. Toto je jediné místo v jazyce, který takové pravidlo používá; pravidlo zajistí, že název nemůže být zcela skrytý před kvalifikací. Bez pravidla by v případě, že by byl název v globálním oboru názvů skrytý v určitém zdrojovém souboru, nebylo by možné určit názvy z tohoto oboru názvů kvalifikovaným způsobem.

V tomto příkladu Imports příkaz vždy odkazuje na globální System obor názvů, nikoli třídu ve zdrojovém souboru.

Imports System   ' Imports the namespace, not the class.

Class System
End Class

Import aliasů

Alias importu definuje alias pro obor názvů nebo typ.

AliasImportsClause
    : Identifier Equals TypeName
    ;
Imports A = N1.N2.A

Namespace N1.N2
    Class A
    End Class
End Namespace

Namespace N3
    Class B
        Inherits A
    End Class
End Namespace

Zde, v rámci zdrojového souboru, A je alias pro N1.N2.A, a tak třída N3.B odvozena od třídy N1.N2.A. Stejný účinek lze získat vytvořením aliasu R pro N1.N2 a následným odkazem R.A:

Imports R = N1.N2

Namespace N3
    Class B
        Inherits R.A
    End Class
End Namespace

Identifikátor aliasu importu musí být jedinečný v prostoru deklarace globálního oboru názvů (nejen globální deklarace oboru názvů ve zdrojovém souboru, ve kterém je definovaný alias importu), i když nehlásí název v prostoru deklarace globálního oboru názvů.

Poznámka. Deklarace v modulu nezavádějí názvy do prostoru obsahující deklarace. Proto platí, že deklarace v modulu má stejný název jako alias importu, i když název deklarace bude přístupný v prostoru obsahující deklarace.

' Error: Alias A conflicts with typename A
Imports A = N3.A

Class A
End Class

Namespace N3
    Class A
    End Class
End Namespace

Globální obor názvů již obsahuje člena A, takže se jedná o chybu pro alias importu, který má tento identifikátor použít. Stejně tak se jedná o chybu dvou nebo více aliasů importu ve stejném zdrojovém souboru, která deklaruje aliasy stejným názvem.

Alias importu může vytvořit alias pro libovolný obor názvů nebo typ. Přístup k oboru názvů nebo typu prostřednictvím aliasu poskytuje přesně stejný výsledek jako přístup k oboru názvů nebo typu prostřednictvím deklarovaného názvu.

Imports R1 = N1
Imports R2 = N1.N2

Namespace N1.N2
    Class A
    End Class
End Namespace

Namespace N3
    Class B
        Private a As N1.N2.A
        Private b As R1.N2.A
        Private c As R2.A
    End Class
End Namespace

Zde názvy N1.N2.A, R1.N2.Aa R2.A jsou ekvivalentní, a všechny odkazují na třídu, jejíž plně kvalifikovaný název je N1.N2.A.

Import určuje přesný název oboru názvů nebo typu, pro který vytváří alias. Musí to být přesný plně kvalifikovaný název oboru názvů nebo typu: nepoužívá normální pravidla pro kvalifikované překlady názvů (které například umožňují přístup k členům základní třídy prostřednictvím odvozené třídy).

Pokud alias importu odkazuje na typ nebo obor názvů, který nelze těmito pravidly vyřešit, bude příkaz importu ignorován (a kompilátor zobrazí upozornění).

Odkaz také nemůže být otevřený obecný typ – všechny obecné typy musí mít zadané platné argumenty typu a všechny argumenty typu musí být přeložitelné výše uvedenými pravidly. Jakákoli nesprávná vazba obecného typu je chyba.

Imports A = G              ' error: since G is an open generic type
Imports B = G(Of Integer)  ' okay
Imports C = Derived.Nested ' warning: Derived.Nested isn't itself a type
Imports D = G(Of Derived.Nested) ' error: Derived.Nested isn't found

Class G(Of T) : End Class

Class Base
    Class Nested : End Class
End Class

Class Derived : Inherits Base
End Class

Module Module1
    Sub Main()
        Dim x As C               ' error: "C" wasn't succesfully defined
        Dim y As Derived.Nested  ' okay
    End Sub
End Module

Deklarace ve zdrojovém souboru mohou stínovat název aliasu importu.

Imports R = N1.N2

Namespace N1.N2
    Class A
    End Class
End Namespace

Namespace N3
    Class R
    End Class

    Class B
        Inherits R.A  ' Error, R has no member A
    End Class
End Namespace

V předchozím příkladu odkaz na R.A v deklaraci B příčin chyby, protože R odkazuje na N3.R, nikoli N1.N2.

Alias importu zpřístupňuje alias v rámci konkrétního zdrojového souboru, ale nepřispívá do podkladového prostoru deklarace žádné nové členy. Jinými slovy, alias importu není tranzitivní, ale spíše ovlivňuje pouze zdrojový soubor, ve kterém k němu dochází.

File1.vb:

Imports R = N1.N2

Namespace N1.N2
    Class A
    End Class
End Namespace

File2.vb:

Class B
    Inherits R.A ' Error, R unknown.
End Class

V předchozím příkladu je rozsah aliasu importu, který zavádí R pouze deklarace ve zdrojovém souboru, ve kterém je obsažen, R neznámý ve druhém zdrojovém souboru.

Importy oborů názvů

Obor názvů importuje všechny členy oboru názvů nebo typu, což umožňuje použít identifikátor každého člena oboru názvů nebo typu bez kvalifikace. V případě typů umožňuje import oboru názvů přístup pouze ke sdíleným členům typu bez nutnosti kvalifikace názvu třídy. Zejména umožňuje používat členy výčtových typů bez kvalifikace.

MembersImportsClause
    : TypeName
    ;

Například:

Imports Colors

Enum Colors
    Red
    Green
    Blue
End Enum

Module M1
    Sub Main()
        Dim c As Colors = Red
    End Sub
End Module

Na rozdíl od aliasu importu nemá import oboru názvů žádná omezení názvů, které importuje, a může importovat obory názvů a typy, jejichž identifikátory jsou již deklarovány v globálním oboru názvů. Názvy importované pravidelným importem jsou stínovány aliasy importu a deklaracemi ve zdrojovém souboru.

V následujícím příkladu A odkazuje N3.A spíše N1.N2.A než na deklarace členů v N3 oboru názvů.

Imports N1.N2

Namespace N1.N2
    Class A
    End Class
End Namespace

Namespace N3
    Class A
    End Class

    Class B
        Inherits A
    End Class
End Namespace

Pokud více importovaných oborů názvů obsahuje členy se stejným názvem (a tento název není jinak stínován aliasem nebo deklarací importu), je odkaz na tento název nejednoznačný a způsobí chybu v době kompilace.

Imports N1
Imports N2

Namespace N1
    Class A
    End Class
End Namespace 

Namespace N2
    Class A
    End Class
End Namespace 

Namespace N3
    Class B
        Inherits A ' Error, A is ambiguous.
    End Class
End Namespace

V předchozím příkladu oba N1 a N2 obsahují člen A. Vzhledem k tomu, že N3 importuje obojí, odkazování A na N3 příčiny chyby v době kompilace. V této situaci lze konflikt vyřešit buď prostřednictvím kvalifikace odkazů na A, nebo zavedením aliasu importu, který vybere konkrétního A, jako v následujícím příkladu:

Imports N1
Imports N2
Imports A = N1.A

Namespace N3
    Class B
        Inherits A ' A means N1.A.
    End Class
End Namespace

Importovat je možné pouze obory názvů, třídy, struktury, výčtové typy a standardní moduly.

Importy oborů názvů XML

Import oboru názvů XML definuje obor názvů nebo výchozí obor názvů pro nekvalifikované výrazy XML obsažené v kompilační jednotce.

XMLNamespaceImportsClause
    : '<' XMLNamespaceAttributeName XMLWhitespace? Equals XMLWhitespace?
      XMLNamespaceValue '>'
    ;

XMLNamespaceValue
    : DoubleQuoteCharacter XMLAttributeDoubleQuoteValueCharacter* DoubleQuoteCharacter
    | SingleQuoteCharacter XMLAttributeSingleQuoteValueCharacter* SingleQuoteCharacter
    ;

Například:

Imports <xmlns:db="http://example.org/database">

Module Test
    Sub Main()
        ' db namespace is "http://example.org/database"
        Dim x = <db:customer><db:Name>Bob</></>

        Console.WriteLine(x.<db:Name>)
    End Sub
End Module

Obor názvů XML, včetně výchozího oboru názvů, lze definovat pouze jednou pro určitou sadu importů. Například:

Imports <xmlns:db="http://example.org/database-one">
' Error: namespace db is already defined
Imports <xmlns:db="http://example.org/database-two">

Jmenné prostory

Programy jazyka Visual Basic jsou uspořádány pomocí oborů názvů. Obory názvů interně uspořádávají program i organizují způsob, jakým jsou prvky programu vystaveny jiným programům.

Na rozdíl od jiných entit jsou obory názvů otevřené a můžou být deklarovány vícekrát ve stejném programu a v mnoha programech, přičemž každá deklarace přispívající členům do stejného oboru názvů. V následujícím příkladu dvě deklarace oboru názvů přispívají do stejného prostoru deklarace a deklarují dvě třídy s plně kvalifikovanými názvy N1.N2.A a N1.N2.B.

Namespace N1.N2
    Class A
    End Class
End Namespace

Namespace N1.N2
    Class B
    End Class
End Namespace

Vzhledem k tomu, že dvě deklarace přispívají ke stejnému prostoru deklarace, bude to chyba, pokud by každá obsahovala deklaraci člena se stejným názvem.

Existuje globální obor názvů, který nemá žádný název a jehož vnořené obory názvů a typy lze vždy získat přístup bez kvalifikace. Oborem člena oboru názvů deklarovaného v globálním oboru názvů je celý text programu. Jinak je obor typu nebo oboru názvů deklarovaný v oboru názvů, jehož plně kvalifikovaný název je N text programu každého oboru názvů, jehož odpovídající plně kvalifikovaný název oboru názvů začíná N nebo je N sám. (Všimněte si, že kompilátor může ve výchozím nastavení vložit deklarace do konkrétního oboru názvů. To nemění skutečnost, že stále existuje globální, nepojmenovaný obor názvů.)

V tomto příkladu může třída B zobrazit třídu A , protože Bobor názvů N1.N2.N3 je koncepčně vnořen v rámci oboru názvů N1.N2.

Namespace N1.N2
    Class A
    End Class
End Namespace

Namespace N1.N2.N3
    Class B
        Inherits A
    End Class
End Namespace

Deklarace jmenného prostoru

Existují tři formy deklarace oboru názvů.

NamespaceDeclaration
    : 'Namespace' NamespaceName StatementTerminator
      NamespaceMemberDeclaration*
      'End' 'Namespace' StatementTerminator
    ;

NamespaceName
    : RelativeNamespaceName
    | 'Global'
    | 'Global' '.' RelativeNamespaceName
    ;

RelativeNamespaceName
    : Identifier ( Period IdentifierOrKeyword )*
    ;

První formulář začíná klíčovým slovem Namespace následovaným názvem relativního oboru názvů. Pokud je relativní název oboru názvů kvalifikovaný, deklarace oboru názvů se považuje za lexicky vnořená do deklarací oboru názvů odpovídajících jednotlivým názvům v kvalifikovaném názvu. Například následující dva obory názvů jsou sémanticky ekvivalentní:

Namespace N1.N2
    Class A
    End Class

    Class B
    End Class
End Namespace 

Namespace N1
    Namespace N2
        Class A
        End Class

        Class B
        End Class
    End Namespace
End Namespace

Druhý formulář začíná klíčovými slovy Namespace Global. Považuje se za to, že všechny jeho deklarace členů byly lexicky umístěny do globálního nepojmenovaného oboru názvů – bez ohledu na výchozí hodnoty poskytované prostředím kompilace. Tato forma deklarace oboru názvů nemusí být lexicky vnořená do žádné jiné deklarace oboru názvů.

Třetí formulář začíná klíčovými slovy Namespace Global následovanými kvalifikovaným identifikátorem N. Považuje se za deklaraci oboru názvů první formy "Namespace N", která byla lexicky umístěna do globálního nepojmenovaného oboru názvů – bez ohledu na výchozí hodnoty poskytované prostředím kompilace. Tato forma deklarace oboru názvů nemusí být lexicky vnořená do žádné jiné deklarace oboru názvů.

Namespace Global       ' Puts N1.A in the global namespace
    Namespace N1
        Class A
        End Class
    End Namespace
End Namespace

Namespace Global.N1    ' Equivalent to the above
    Class A
    End Class
End Namespace

Namespace N1           ' May or may not be equivalent to the above,
    Class A            ' depending on defaults provided by the
    End Class          ' compilation environment
End Namespace

Při práci se členy oboru názvů není důležité, pokud je konkrétní člen deklarován. Pokud dva programy definují entitu se stejným názvem ve stejném oboru názvů, pokus o překlad názvu v oboru názvů způsobí chybu nejednoznačnosti.

Obory názvů jsou podle definice Public, takže deklarace oboru názvů nemůže obsahovat žádné modifikátory přístupu.

Členové oboru názvů

Členy oboru názvů mohou být pouze deklarace oboru názvů a deklarace typů. Deklarace typů můžou mít Public nebo Friend mají přístup. Výchozí přístup pro typy je Friend přístup.

NamespaceMemberDeclaration
    : NamespaceDeclaration
    | TypeDeclaration
    ;

TypeDeclaration
    : ModuleDeclaration
    | NonModuleDeclaration
    ;

NonModuleDeclaration
    : EnumDeclaration
    | StructureDeclaration
    | InterfaceDeclaration
    | ClassDeclaration
    | DelegateDeclaration
    ;