Sdílet prostřednictvím


Typy v jazyce Visual Basic

Dvě základní kategorie typů v jazyce Visual Basic jsou typy hodnot a odkazové typy. Primitivní typy (kromě řetězců), výčty a struktury jsou typy hodnot. Třídy, řetězce, standardní moduly, rozhraní, pole a delegáty jsou odkazové typy.

Každý typ má výchozí hodnotu, což je hodnota přiřazená proměnným tohoto typu při inicializaci.

TypeName
    : ArrayTypeName
    | NonArrayTypeName
    ;

NonArrayTypeName
    : SimpleTypeName
    | NullableTypeName
    ;

SimpleTypeName
    : QualifiedTypeName
    | BuiltInTypeName
    ;

QualifiedTypeName
    : Identifier TypeArguments? (Period IdentifierOrKeyword TypeArguments?)*
    | 'Global' Period IdentifierOrKeyword TypeArguments?
      (Period IdentifierOrKeyword TypeArguments?)*
    ;

TypeArguments
    : OpenParenthesis 'Of' TypeArgumentList CloseParenthesis
    ;

TypeArgumentList
    : TypeName ( Comma TypeName )*
    ;

BuiltInTypeName
    : 'Object'
    | PrimitiveTypeName
    ;

TypeModifier
    : AccessModifier
    | 'Shadows'
    ;

IdentifierModifiers
    : NullableNameModifier? ArrayNameModifier?
    ;

Typy hodnot a odkazové typy

I když typy hodnot a odkazové typy můžou být podobné z hlediska syntaxe deklarace a použití, jejich sémantika je odlišná.

Odkazové typy jsou uloženy v haldě za běhu; mohou být přístupné pouze prostřednictvím odkazu na toto úložiště. Vzhledem k tomu, že k typům odkazů se vždy přistupuje prostřednictvím odkazů, je jejich životnost spravována rozhraním .NET Framework. Nevyřízené odkazy na konkrétní instanci jsou sledovány a instance je zničena pouze v případě, že žádné další odkazy nezůstanou. Proměnná typu odkazu obsahuje odkaz na hodnotu tohoto typu, hodnotu odvozeného typu nebo hodnotu null. Hodnota null odkazuje na nic; Není možné nic dělat s hodnotou null s výjimkou přiřazení. Přiřazení proměnné typu odkazu vytvoří kopii odkazu místo kopie odkazované hodnoty. Pro proměnnou typu odkazu je výchozí hodnota null.

Typy hodnot jsou uloženy přímo v zásobníku, a to buď v poli, nebo v jiném typu; k jejich úložišti je možné přistupovat pouze přímo. Vzhledem k tomu, že typy hodnot jsou uloženy přímo v proměnných, jejich životnost je určena životností proměnné, která je obsahuje. Pokud je umístění obsahující instanci typu hodnoty zničeno, instance typu hodnoty je také zničena. K typům hodnot se vždy přistupuje přímo; Není možné vytvořit odkaz na typ hodnoty. Zakázání takového odkazu znemožňuje odkazovat na instanci třídy hodnot, která byla zničena. Vzhledem k tomu, že typy hodnot jsou vždy NotInheritable, proměnná typu hodnoty vždy obsahuje hodnotu tohoto typu. Z tohoto důvodu nemůže být hodnota typu hodnoty null, ani nemůže odkazovat na objekt odvozeného typu. Přiřazení proměnné typu hodnoty vytvoří kopii přiřazené hodnoty. Pro proměnnou typu hodnoty je výchozí hodnota výsledkem inicializace každého člena proměnné typu na výchozí hodnotu.

Následující příklad ukazuje rozdíl mezi odkazovými typy a typy hodnot:

Class Class1
    Public Value As Integer = 0
End Class

Module Test
    Sub Main()
        Dim val1 As Integer = 0
        Dim val2 As Integer = val1
        val2 = 123
        Dim ref1 As Class1 = New Class1()
        Dim ref2 As Class1 = ref1
        ref2.Value = 123
        Console.WriteLine("Values: " & val1 & ", " & val2)
        Console.WriteLine("Refs: " & ref1.Value & ", " & ref2.Value)
    End Sub
End Module

Výstupem programu je:

Values: 0, 123
Refs: 123, 123

Přiřazení k místní proměnné val2 nemá vliv na místní proměnnou val1 , protože obě místní proměnné mají typ hodnoty (typ Integer) a každá místní proměnná typu hodnoty má vlastní úložiště. Naproti tomu přiřazení ref2.Value = 123; ovlivňuje objekt, který a ref1ref2 odkazuje.

Jedním z poznámek o systému typů rozhraní .NET Framework je, že i když struktury, výčty a primitivní typy (s výjimkou String) jsou typy hodnot, všechny dědí z referenčních typů. Struktury a primitivní typy dědí z referenčního typu System.ValueType, který dědí z Object. Výčtové typy dědí z referenčního typu System.Enum, který dědí z System.ValueType.

Typy hodnot, které mohou být null

U typů hodnot lze modifikátor přidat do názvu typu, ? který představuje verzi tohoto typu s možnou hodnotou null .

NullableTypeName
    : NonArrayTypeName '?'
    ;

NullableNameModifier
    : '?'
    ;

Typ hodnoty s možnou hodnotou null může obsahovat stejné hodnoty jako verze typu, která není nullable, a také hodnotu null. Proto pro typ hodnoty s možnou hodnotou null přiřazování Nothing proměnné typu nastaví hodnotu proměnné na hodnotu null, nikoli nulovou hodnotu typu hodnoty. Například:

Dim x As Integer = Nothing
Dim y As Integer? = Nothing

' Prints zero
Console.WriteLine(x)
' Prints nothing (because the value of y is the null value)
Console.WriteLine(y)

Proměnnou lze také deklarovat jako typ hodnoty null, a to tak, že do názvu proměnné vložíte modifikátor typu s možnou hodnotou null. Pro přehlednost není platný modifikátor typu s možnou hodnotou null u názvu proměnné i názvu typu ve stejné deklaraci. Vzhledem k tomu, že typy s možnou hodnotou null jsou implementovány pomocí typu System.Nullable(Of T), typ T? je synonymem pro typ System.Nullable(Of T)a dva názvy lze zaměnitelně. ? Modifikátor nelze umístit na typ, který je již nullable, a proto není možné deklarovat typ Integer?? nebo System.Nullable(Of Integer)?.

Typ T? hodnoty s možnou hodnotou null má členy System.Nullable(Of T) a také všechny operátory nebo převody zvednuty ze základního typu T do typu T?. Zvedání operátorů a převodů ze základního typu se ve většině případů nahrazují typy hodnot s možnou hodnotou null pro typy hodnot, které nemají hodnotu null. To umožňuje mnoho stejných převodů a operací, které platí i pro T použití T? .

Implementace rozhraní

Deklarace struktury a třídy mohou deklarovat, že implementují sadu typů rozhraní prostřednictvím jedné nebo více Implements klauzulí.

TypeImplementsClause
    : 'Implements' TypeImplements StatementTerminator
    ;

TypeImplements
    : NonArrayTypeName ( Comma NonArrayTypeName )*
    ;

Všechny typy zadané v Implements klauzuli musí být rozhraní a typ musí implementovat všechny členy rozhraní. Například:

Interface ICloneable
    Function Clone() As Object
End Interface 

Interface IComparable
    Function CompareTo(other As Object) As Integer
End Interface 

Structure ListEntry
    Implements ICloneable, IComparable

    ...

    Public Function Clone() As Object Implements ICloneable.Clone
        ...
    End Function 

    Public Function CompareTo(other As Object) As Integer _
        Implements IComparable.CompareTo
        ...
    End Function 
End Structure

Typ, který implementuje rozhraní také implicitně implementuje všechna základní rozhraní rozhraní. To platí i v případě, že typ explicitně nevypisuje všechna základní rozhraní v klauzuli Implements . V tomto příkladu TextBox struktura implementuje obě IControl a ITextBox.

Interface IControl
    Sub Paint()
End Interface 

Interface ITextBox
    Inherits IControl

    Sub SetText(text As String)
End Interface 

Structure TextBox
    Implements ITextBox

    ...

    Public Sub Paint() Implements ITextBox.Paint
        ...
    End Sub

    Public Sub SetText(text As String) Implements ITextBox.SetText
        ...
    End Sub
End Structure

Deklarování, že typ implementuje rozhraní a sám o sobě nehlásí nic v prostoru deklarace typu. Proto je platné implementovat dvě rozhraní s metodou se stejným názvem.

Typy nemohou implementovat parametr typu samostatně, i když může zahrnovat parametry typu, které jsou v oboru.

Class C1(Of V)
    Implements V  ' Error, can't implement type parameter directly
    Implements IEnumerable(Of V)  ' OK, not directly implementing

    ...
End Class

Obecná rozhraní lze implementovat vícekrát pomocí různých argumentů typu. Obecný typ však nemůže implementovat obecné rozhraní pomocí parametru typu, pokud zadaný parametr typu (bez ohledu na omezení typu) by se mohl překrývat s jinou implementací tohoto rozhraní. Například:

Interface I1(Of T)
End Interface

Class C1
    Implements I1(Of Integer)
    Implements I1(Of Double)    ' OK, no overlap
End Class

Class C2(Of T)
    Implements I1(Of Integer)
    Implements I1(Of T)         ' Error, T could be Integer
End Class

Primitivní typy

Primitivní typy jsou identifikovány prostřednictvím klíčových slov, což jsou aliasy pro předdefinované typy v System oboru názvů. Primitivní typ je zcela nerozlišitelný od typu, který aliasy: zápis rezervovaného slova Byte je úplně stejný jako psaní System.Byte. Primitivní typy se také označují jako vnitřní typy.

PrimitiveTypeName
    : NumericTypeName
    | 'Boolean'
    | 'Date'
    | 'Char'
    | 'String'
    ;

NumericTypeName
    : IntegralTypeName
    | FloatingPointTypeName
    | 'Decimal'
    ;

IntegralTypeName
    : 'Byte' | 'SByte' | 'UShort' | 'Short' | 'UInteger'
    | 'Integer' | 'ULong' | 'Long'
    ;

FloatingPointTypeName
    : 'Single' | 'Double'
    ;

Vzhledem k tomu, že primitivní typ aliasy běžného typu, má každý primitivní typ členy. Má například Integer členy deklarované v System.Int32. Literály lze považovat za instance odpovídajících typů.

  • Primitivní typy se liší od jiných typů struktury v tom, že umožňují určité další operace:

  • Primitivní typy umožňují vytváření hodnot zápisem literálů. Jedná se například 123I o literál typu Integer.

  • Je možné deklarovat konstanty primitivních typů.

  • Pokud jsou operandy výrazu všechny primitivní konstanty typu, je možné, aby kompilátor vyhodnocoval výraz v době kompilace. Takový výraz se označuje jako konstantní výraz.

Visual Basic definuje následující primitivní typy:

  • Celočíselné typy Byte hodnot (1 bajtové celé číslo bez znaménka), SByte (1 bajtové celé číslo), UShort (2 bajtové celé číslo bez znaménka), Short (2 bajtové UInteger celé číslo), (4 bajtové celé číslo bez znaménka), Integer (4 bajtové celé číslo), ULong (8 bajtové celé číslo bez znaménka) a Long (8 bajtové celé číslo se znaménkem). Tyto typy se mapují na System.Byte, , System.UInt32System.Int16System.UInt16System.Int32System.SByte, System.UInt64 a System.Int64, v uvedeném pořadí. Výchozí hodnota celočíselného typu je ekvivalentní literálu 0.

  • Typy hodnotsch Single (4bajtů s plovoucí desetinou čárkou) a Double (8 bajtů s plovoucí desetinou čárkou) Tyto typy se mapují na System.Single a System.Doublev uvedeném pořadí. Výchozí hodnota typu s plovoucí desetinou čárkou je ekvivalentní literálu 0.

  • Typ Decimal (desetinná hodnota 16 bajtů), která se mapuje na System.Decimal. Výchozí hodnota desetinné čárky je ekvivalentní literálu 0D.

  • Typ Boolean hodnoty, který představuje hodnotu pravdy, obvykle výsledek relační nebo logické operace. Literál je typu System.Boolean. Výchozí hodnota Boolean typu je ekvivalentní literálu False.

  • Typ Date hodnoty, který představuje datum nebo čas a mapuje se na System.DateTime. Výchozí hodnota Date typu je ekvivalentní literálu # 01/01/0001 12:00:00AM #.

  • Typ Char hodnoty, který představuje jeden znak Unicode a mapuje na System.Char. Výchozí hodnota Char typu je ekvivalentní konstantnímu výrazu ChrW(0).

  • Typ String odkazu, který představuje posloupnost znaků Unicode a mapuje na System.String. Výchozí hodnota String typu je hodnota null.

Výčty

Výčty jsou typy hodnot, které dědí z System.Enum a symbolicky představují sadu hodnot jednoho z primitivních integrálních typů.

EnumDeclaration
    : Attributes? TypeModifier* 'Enum' Identifier
      ( 'As' NonArrayTypeName )? StatementTerminator
      EnumMemberDeclaration+
      'End' 'Enum' StatementTerminator
    ;

Pro typ Evýčtu je výchozí hodnota hodnota vytvořená výrazem CType(0, E).

Základní typ výčtu musí být celočíselný typ, který může představovat všechny hodnoty výčtu definované v výčtu. Je-li zadán základní typ, musí být , , , , , , Integer, , ULong, Longnebo jeden z jejich odpovídajících typů v System oboru názvů. UIntegerShortUShortSByteByte Pokud není explicitně zadán žádný podkladový typ, je výchozí Integerhodnota .

Následující příklad deklaruje výčet s základním typem Long:

Enum Color As Long
    Red
    Green
    Blue
End Enum

Vývojář se může rozhodnout použít základní typ Long, jako v příkladu, povolit použití hodnot, které jsou v rozsahu Long, ale ne v rozsahu Integer, nebo zachovat tuto možnost pro budoucnost.

Členy výčtu

Členy výčtu jsou výčtové hodnoty deklarované v výčtu a členy zděděné z třídy System.Enum.

Rozsah členu výčtu je tělo deklarace výčtu. To znamená, že mimo deklaraci výčtu musí být člen výčtu vždy kvalifikovaný (pokud typ není speciálně importován do oboru názvů prostřednictvím importu oboru názvů).

Pořadí deklarací pro deklarace členů výčtu je významné, pokud jsou vynechány hodnoty konstantního výrazu. Členy výčtu mají implicitně Public přístup pouze. U deklarací členů výčtu nejsou povoleny žádné modifikátory přístupu.

EnumMemberDeclaration
    : Attributes? Identifier ( Equals ConstantExpression )? StatementTerminator
    ;

Hodnoty výčtu

Výčtové hodnoty v seznamu členů výčtu jsou deklarovány jako konstanty zadané jako základní typ výčtu a mohou se objevit všude, kde jsou požadovány konstanty. Definice člena výčtu s = dává přidruženému členu hodnotu označenou konstantním výrazem. Konstantní výraz musí být vyhodnocen jako celočíselný typ, který se implicitně konvertibilní na základní typ a musí být v rozsahu hodnot, které mohou být reprezentovány základním typem. Následující příklad je v chybě, protože konstantní hodnoty 1.5, 2.3a 3.3 nejsou implicitně konvertibilní na základní celočíselný typ Long s striktní sémantikou.

Option Strict On

Enum Color As Long
    Red = 1.5
    Green = 2.3
    Blue = 3.3
End Enum

Více členů výčtu může sdílet stejnou přidruženou hodnotu, jak je znázorněno níže:

Enum Color
    Red
    Green
    Blue
    Max = Blue
End Enum

Příklad ukazuje výčet, který má dva členy výčtu – Blue a Max -, které mají stejnou přidruženou hodnotu.

Pokud první definice hodnoty enumerátoru ve výčtu nemá žádný inicializátor, hodnota odpovídající konstanty je 0. Definice hodnoty výčtu bez inicializátoru poskytuje výčtu hodnotu získanou zvýšením hodnoty předchozího výčtu o 1hodnotu . Tato zvýšená hodnota musí být v rozsahu hodnot, které mohou být reprezentovány základním typem.

Enum Color
    Red
    Green = 10
    Blue
End Enum 

Module Test
    Sub Main()
        Console.WriteLine(StringFromColor(Color.Red))
        Console.WriteLine(StringFromColor(Color.Green))
        Console.WriteLine(StringFromColor(Color.Blue))
    End Sub

    Function StringFromColor(c As Color) As String
        Select Case c
            Case Color.Red
                Return String.Format("Red = " & CInt(c))

            Case Color.Green
                Return String.Format("Green = " & CInt(c))

            Case Color.Blue
                Return String.Format("Blue = " & CInt(c))

            Case Else
                Return "Invalid color"
        End Select
    End Function
End Module

Výše uvedený příklad zobrazí hodnoty výčtu a jejich přidružené hodnoty. Výstup je:

Red = 0
Green = 10
Blue = 11

Důvody hodnot jsou následující:

  • Hodnota Red výčtu je automaticky přiřazena hodnotu 0 (protože nemá žádný inicializátor a je prvním členem hodnoty výčtu).

  • Hodnota Green výčtu je explicitně uvedena hodnota 10.

  • Hodnota Blue výčtu se automaticky přiřadí hodnotě větší než hodnota výčtu, která před ní textově předchází.

Konstantní výraz nemusí přímo nebo nepřímo používat hodnotu vlastní přidružené hodnoty výčtu (to znamená, že cykličnost ve výrazu konstanty není povolena). Následující příklad je neplatný, protože deklarace A a B jsou cyklické.

Enum Circular
    A = B
    B
End Enum

A závisí na B explicitně a B závisí na A implicitně.

Vyučování

Třída je datová struktura, která může obsahovat datové členy (konstanty, proměnné a události), členy funkce (metody, vlastnosti, indexery, operátory a konstruktory) a vnořené typy. Třídy jsou odkazové typy.

ClassDeclaration
    : Attributes? ClassModifier* 'Class' Identifier TypeParameterList? StatementTerminator
      ClassBase?
      TypeImplementsClause*
      ClassMemberDeclaration*
      'End' 'Class' StatementTerminator
    ;

ClassModifier
    : TypeModifier
    | 'MustInherit'
    | 'NotInheritable'
    | 'Partial'
    ;

Následující příklad ukazuje třídu, která obsahuje každý druh člena:

Class AClass
    Public Sub New()
        Console.WriteLine("Constructor")
    End Sub

    Public Sub New(value As Integer)
        MyVariable = value
        Console.WriteLine("Constructor")
    End Sub

    Public Const MyConst As Integer = 12
    Public MyVariable As Integer = 34

    Public Sub MyMethod()
        Console.WriteLine("MyClass.MyMethod")
    End Sub

    Public Property MyProperty() As Integer
        Get
            Return MyVariable
        End Get

        Set (value As Integer)
            MyVariable = value
        End Set
    End Property

    Default Public Property Item(index As Integer) As Integer
        Get
            Return 0
        End Get

        Set (value As Integer)
            Console.WriteLine("Item(" & index & ") = " & value)
        End Set
    End Property

    Public Event MyEvent()

    Friend Class MyNestedClass
    End Class 
End Class

Následující příklad ukazuje použití těchto členů:

Module Test

    ' Event usage.
    Dim WithEvents aInstance As AClass

    Sub Main()
        ' Constructor usage.
        Dim a As AClass = New AClass()
        Dim b As AClass = New AClass(123)

        ' Constant usage.
        Console.WriteLine("MyConst = " & AClass.MyConst)

        ' Variable usage.
        a.MyVariable += 1
        Console.WriteLine("a.MyVariable = " & a.MyVariable)

        ' Method usage.
        a.MyMethod()

        ' Property usage.
        a.MyProperty += 1
        Console.WriteLine("a.MyProperty = " & a.MyProperty)
        a(1) = 1

        ' Event usage.
        aInstance = a
    End Sub 

    Sub MyHandler() Handles aInstance.MyEvent
        Console.WriteLine("Test.MyHandler")
    End Sub 
End Module

Existují dva modifikátory MustInherit specifické pro třídu a NotInheritable. Není platné je zadat oba.

Základní specifikace třídy

Deklarace třídy může obsahovat specifikaci základního typu, která definuje přímý základní typ třídy.

ClassBase
    : 'Inherits' NonArrayTypeName StatementTerminator
    ;

Pokud deklarace třídy nemá žádný explicitní základní typ, přímý základní typ je implicitně Object. Například:

Class Base
End Class

Class Derived
    Inherits Base
End Class

Základní typy nemohou být parametrem typu samostatně, i když mohou zahrnovat parametry typu, které jsou v oboru.

Class C1(Of V) 
End Class

Class C2(Of V)
    Inherits V    ' Error, type parameter used as base class 
End Class

Class C3(Of V)
    Inherits C1(Of V)    ' OK: not directly inheriting from V.
End Class

Třídy mohou být odvozeny pouze z Object tříd a tříd. Třída je neplatná pro odvození od System.ValueType, System.Enum, System.ArraySystem.MulticastDelegate nebo System.Delegate. Obecná třída nemůže odvozovat nebo System.Attribute od třídy, která je z ní odvozena.

Každá třída má přesně jednu přímou základní třídu a cykličnost odvození je zakázána. Není možné odvodit z NotInheritable třídy a doména přístupnosti základní třídy musí být stejná jako nebo nadmnožina domény přístupnosti samotné třídy.

Členové třídy

Členy třídy se skládají z členů zavedených deklaracemi členů třídy a členy zděděné z jeho přímé základní třídy.

ClassMemberDeclaration
    : NonModuleDeclaration
    | EventMemberDeclaration
    | VariableMemberDeclaration
    | ConstantMemberDeclaration
    | MethodMemberDeclaration
    | PropertyMemberDeclaration
    | ConstructorMemberDeclaration
    | OperatorDeclaration
    ;

Deklarace člena třídy může mít Public, ProtectedFriend, , Protected Friend, nebo Private přístup. Pokud deklarace člena třídy neobsahuje modifikátor přístupu, deklarace se ve výchozím nastavení použije pro Public přístup, pokud se nejedná o deklaraci proměnné. V takovém případě je výchozí pro Private přístup.

Obor člena třídy je tělo třídy, ve kterém dojde k deklaraci členu, plus seznam omezení této třídy (pokud je obecný a má omezení). Pokud má Friend člen přístup, jeho obor se vztahuje na tělo třídy jakékoli odvozené třídy ve stejném programu nebo jakékoli sestavení, které byl udělen Friend přístup, a pokud člen má Public, Protectednebo Protected Friend přístup, jeho rozsah rozšiřuje na tělo třídy jakékoli odvozené třídy v libovolném programu.

Struktury

Struktury jsou typy hodnot, které dědí z System.ValueType. Struktury jsou podobné třídám, které představují datové struktury, které mohou obsahovat datové členy a členy funkce. Na rozdíl od tříd však struktury nevyžadují přidělení haldy.

StructureDeclaration
    : Attributes? StructureModifier* 'Structure' Identifier
      TypeParameterList? StatementTerminator
      TypeImplementsClause*
      StructMemberDeclaration*
      'End' 'Structure' StatementTerminator
    ;

StructureModifier
    : TypeModifier
    | 'Partial'
    ;

V případě tříd je možné, aby dvě proměnné odkazovaly na stejný objekt, a proto operace s jednou proměnnou ovlivnit objekt odkazovaný druhou proměnnou. U struktur mají proměnné vlastní kopii jinýchShared než dat, takže není možné, aby operace na jedné z nich ovlivnily druhý, jak ukazuje následující příklad:

Structure Point
    Public x, y As Integer

    Public Sub New(x As Integer, y As Integer)
        Me.x = x
        Me.y = y
    End Sub
End Structure

Při výše uvedené deklaraci následující kód vypíše hodnotu 10:

Module Test
    Sub Main()
        Dim a As New Point(10, 10)
        Dim b As Point = a

        a.x = 100
        Console.WriteLine(b.x)
    End Sub
End Module

Přiřazení a k b vytvoří kopii hodnoty, a b proto není ovlivněno přiřazením k a.x. Kdyby byl Point místo toho deklarován jako třída, výstup by byl 100 , protože a a b by odkazovaly na stejný objekt.

Členy struktury

Členy struktury jsou členy zavedené deklaracemi členů struktury a členy zděděné z System.ValueType.

StructMemberDeclaration
    : NonModuleDeclaration
    | VariableMemberDeclaration
    | ConstantMemberDeclaration
    | EventMemberDeclaration
    | MethodMemberDeclaration
    | PropertyMemberDeclaration
    | ConstructorMemberDeclaration
    | OperatorDeclaration
    ;

Každá struktura implicitně má Public konstruktor instance bez parametrů, který vytváří výchozí hodnotu struktury. V důsledku toho není možné deklaraci typu struktury deklarovat konstruktor instance bez parametrů. Typ struktury však umožňuje deklarovat parametrizované konstruktory instance, jako v následujícím příkladu:

Structure Point
    Private x, y As Integer

    Public Sub New(x As Integer, y As Integer)
        Me.x = x
        Me.y = y
    End Sub
End Structure

Vzhledem k výše uvedené deklaraci vytvoří následující příkazy jak s, tak y inicializovaným x na nuluPoint.

Dim p1 As Point = New Point()
Dim p2 As Point = New Point(0, 0)

Vzhledem k tomu, že struktury přímo obsahují hodnoty polí (nikoli odkazy na tyto hodnoty), nemohou struktury obsahovat pole, která přímo nebo nepřímo odkazují. Například následující kód není platný:

Structure S1
    Dim f1 As S2
End Structure

Structure S2
    ' This would require S1 to contain itself.
    Dim f1 As S1
End Structure

Za normálních okolností může mít Publicdeklarace člena struktury pouze , Friendnebo Private přístup, ale při přepsání členů zděděných z Objecta ProtectedProtected Friend přístup lze použít také. Pokud deklarace člena struktury neobsahuje modifikátor přístupu, deklarace je výchozí pro Public přístup. Obor členu deklarovaného strukturou je tělo struktury, ve kterém se deklarace vyskytuje, a omezení této struktury (pokud byla obecná a měla omezení).

Standardní moduly

Standardní modul je typ, jehož členy jsou implicitně Shared a vymezeny na prostor deklarace standardního modulu obsahujícího obor názvů, nikoli pouze na samotnou deklaraci standardního modulu. Standardní moduly nemusí být nikdy vytvořena instance. Jedná se o chybu deklarování proměnné standardního typu modulu.

ModuleDeclaration
    : Attributes? TypeModifier* 'Module' Identifier StatementTerminator
      ModuleMemberDeclaration*
      'End' 'Module' StatementTerminator
    ;

Člen standardního modulu má dva plně kvalifikované názvy, jeden bez standardního názvu modulu a jeden se standardním názvem modulu. Více než jeden standardní modul v oboru názvů může definovat člen s konkrétním názvem; nekvalifikované odkazy na název mimo některý z modulů jsou nejednoznačné. Například:

Namespace N1
    Module M1
        Sub S1()
        End Sub

        Sub S2()
        End Sub
    End Module

    Module M2
        Sub S2()
        End Sub
    End Module

    Module M3
        Sub Main()
            S1()       ' Valid: Calls N1.M1.S1.
            N1.S1()    ' Valid: Calls N1.M1.S1.
            S2()       ' Not valid: ambiguous.
            N1.S2()    ' Not valid: ambiguous.
            N1.M2.S2() ' Valid: Calls N1.M2.S2.
        End Sub
    End Module
End Namespace

Modul může být deklarován pouze v oboru názvů a nemusí být vnořen v jiném typu. Standardní moduly nemusí implementovat rozhraní, implicitně jsou odvozeny od Objecta mají pouze Shared konstruktory.

Standardní členy modulu

Členy standardního modulu jsou členy představené jeho deklaracemi členů a členy zděděné z Object. Standardní moduly mohou mít jakýkoli typ členu s výjimkou konstruktorů instancí. Všechny standardní členy typu modulu jsou implicitně Shared.

ModuleMemberDeclaration
    : NonModuleDeclaration
    | VariableMemberDeclaration
    | ConstantMemberDeclaration
    | EventMemberDeclaration
    | MethodMemberDeclaration
    | PropertyMemberDeclaration
    | ConstructorMemberDeclaration
    ;

Za normálních okolností může mít Publicstandardní deklarace členu modulu pouze , Friendnebo Private přístup, ale při přepsání členů zděděných z Object, Protected modifikátory přístupu a Protected Friend modifikátory přístupu mohou být zadány. Pokud standardní deklarace člena modulu neobsahuje modifikátor přístupu, deklarace se ve výchozím nastavení použije pro Public přístup, pokud se nejedná o proměnnou, která má výchozí Private přístup.

Jak jsme už uvedli, obor standardního člena modulu je deklarace obsahující standardní deklaraci modulu. Členové zdědění z Object tohoto speciálního oboru nejsou zahrnuti; tito členové nemají žádný obor a musí být vždy kvalifikovaní s názvem modulu. Pokud má Friend člen přístup, jeho obor se vztahuje pouze na členy oboru názvů deklarované ve stejném programu nebo sestaveních, které byly uděleny Friend .

Rozhraní

Rozhraní jsou odkazové typy, které jiné typy implementují, aby zajistily, že podporují určité metody. Rozhraní se nikdy nevytvořilo přímo a nemá žádnou skutečnou reprezentaci – jiné typy musí být převedeny na typ rozhraní. Rozhraní definuje kontrakt. Třída nebo struktura, která implementuje rozhraní, musí dodržovat svůj kontrakt.

InterfaceDeclaration
    : Attributes? TypeModifier* 'Interface' Identifier
      TypeParameterList? StatementTerminator
      InterfaceBase*
      InterfaceMemberDeclaration*
      'End' 'Interface' StatementTerminator
    ;

Následující příklad ukazuje rozhraní, které obsahuje výchozí vlastnost Item, událost E, metodu Fa vlastnost P:

Interface IExample
    Default Property Item(index As Integer) As String

    Event E()

    Sub F(value As Integer)

    Property P() As String
End Interface

Rozhraní mohou využívat více dědičnosti. V následujícím příkladu rozhraní IComboBox dědí z obou ITextBox a IListBox:

Interface IControl
    Sub Paint()
End Interface 

Interface ITextBox
    Inherits IControl

    Sub SetText(text As String)
End Interface 

Interface IListBox
    Inherits IControl

    Sub SetItems(items() As String)
End Interface 

Interface IComboBox
    Inherits ITextBox, IListBox 
End Interface

Třídy a struktury mohou implementovat více rozhraní. V následujícím příkladu je třída EditBox odvozena z třídy Control a implementuje obě IControl a IDataBound:

Interface IDataBound
    Sub Bind(b As Binder)
End Interface 

Public Class EditBox
    Inherits Control
    Implements IControl, IDataBound

    Public Sub Paint() Implements IControl.Paint
        ...
    End Sub

    Public Sub Bind(b As Binder) Implements IDataBound.Bind
        ...
    End Sub
End Class

Dědičnost rozhraní

Základní rozhraní rozhraní jsou explicitní základní rozhraní a jejich základní rozhraní. Jinými slovy, množina základních rozhraní je úplné tranzitivní uzavření explicitních základních rozhraní, jejich explicitních základních rozhraní a tak dále. Pokud deklarace rozhraní nemá žádný explicitní základ rozhraní, neexistuje žádné základní rozhraní pro typ - rozhraní nedědí z Object (ačkoli mají rozšiřující převod na Object).

InterfaceBase
    : 'Inherits' InterfaceBases StatementTerminator
    ;

InterfaceBases
    : NonArrayTypeName ( Comma NonArrayTypeName )*
    ;

V následujícím příkladu jsou základní rozhraní IComboBox jsou IControl, ITextBoxa IListBox.

Interface IControl
    Sub Paint()
End Interface 

Interface ITextBox
    Inherits IControl

    Sub SetText(text As String)
End Interface 

Interface IListBox
    Inherits IControl

    Sub SetItems(items() As String)
End Interface 

Interface IComboBox
    Inherits ITextBox, IListBox 
End Interface

Rozhraní dědí všechny členy jeho základních rozhraní. Jinými slovy, IComboBox výše uvedené rozhraní dědí členy SetText a SetItems také Paint.

Třída nebo struktura, která implementuje rozhraní také implicitně implementuje všechna základní rozhraní rozhraní.

Pokud se v přechodném uzavření základních rozhraní zobrazí více než jedno rozhraní, přispívá pouze jeho členy k odvozené rozhraní jednou. Typ, který implementuje odvozené rozhraní, musí implementovat pouze metody násobení definovaného základního rozhraní jednou. V následujícím příkladu Paint je nutné implementovat pouze jednou, i když třída implementuje IComboBox a IControl.

Class ComboBox
    Implements IControl, IComboBox

    Sub SetText(text As String) Implements IComboBox.SetText
    End Sub

    Sub SetItems(items() As String) Implements IComboBox.SetItems
    End Sub

    Sub Print() Implements IComboBox.Paint
    End Sub
End Class

Klauzule Inherits nemá žádný vliv na jiné Inherits klauzule. V následujícím příkladu IDerived musí být kvalifikovat název s INestedIBase.

Interface IBase
    Interface INested
        Sub Nested()
    End Interface

    Sub Base()
End Interface

Interface IDerived
    Inherits IBase, INested   ' Error: Must specify IBase.INested.
End Interface

Doména přístupnosti základního rozhraní musí být stejná jako nebo nadmnožina domény přístupnosti samotného rozhraní.

Členy rozhraní

Členy rozhraní se skládají z členů zavedených jeho deklaracemi členů a členy zděděné ze základních rozhraní.

InterfaceMemberDeclaration
    : NonModuleDeclaration
    | InterfaceEventMemberDeclaration
    | InterfaceMethodMemberDeclaration
    | InterfacePropertyMemberDeclaration
    ;

I když rozhraní nedědí členy z Object, protože každá třída nebo struktura, která implementuje rozhraní dědí z Object, členy Object, včetně rozšiřujících metod, jsou považovány za členy rozhraní a lze volat na rozhraní přímo bez nutnosti přetypování na Object. Například:

Interface I1
End Interface

Class C1
    Implements I1
End Class

Module Test
    Sub Main()
        Dim i As I1 = New C1()
        Dim h As Integer = i.GetHashCode()
    End Sub
End Module

Členové rozhraní se stejným názvem jako členové implicitně stínových ObjectObject členů. Členy rozhraní mohou být pouze vnořené typy, metody, vlastnosti a události. Metody a vlastnosti nemusí obsahovat tělo. Členy rozhraní jsou implicitně Public a nemusí určovat modifikátor přístupu. Obor člena deklarovaného v rozhraní je tělo rozhraní, ve kterém se deklarace vyskytuje, plus seznam omezení tohoto rozhraní (pokud je obecný a má omezení).

Pole

Matice je referenční typ, který obsahuje proměnné, ke kterým se přistupuje prostřednictvím indexů odpovídajících 1:1, s pořadím proměnných v poli. Proměnné obsažené v matici, označované také jako prvky pole, musí být všechny stejného typu a tento typ se nazývá typ prvku pole.

ArrayTypeName
    : NonArrayTypeName ArrayTypeModifiers
    ;

ArrayTypeModifiers
    : ArrayTypeModifier+
    ;

ArrayTypeModifier
    : OpenParenthesis RankList? CloseParenthesis
    ;

RankList
    : Comma*
    ;

ArrayNameModifier
    : ArrayTypeModifiers
    | ArraySizeInitializationModifier
    ;

Prvky pole přicházejí do existence při vytvoření instance pole a přestanou existovat, když je instance pole zničena. Každý prvek pole je inicializován na výchozí hodnotu jeho typu. System.Array Typ je základním typem všech typů polí a nemusí být vytvořena instance. Každý typ pole dědí členy deklarované typem System.Array a je k němu konvertibilní (a Object). Jednorozměrný typ pole s prvkem T také implementuje rozhraní System.Collections.Generic.IList(Of T) a IReadOnlyList(Of T); pokud T je typ odkazu, pak typ pole také implementuje IList(Of U) a IReadOnlyList(Of U) pro všechny U , které mají rozšiřující odkaz převod z T.

Pole má pořadí , které určuje počet indexů přidružených k jednotlivým prvkům pole. Pořadí matice určuje počet dimenzí pole. Například pole s pořadím jednoho se nazývá jednorozměrné pole a pole s pořadím větší než jednorozměrné se nazývá multidimenzionální pole.

Následující příklad vytvoří jednorozměrné pole celočíselné hodnoty, inicializuje prvky pole a pak každý z nich vytiskne:

Module Test
    Sub Main()
        Dim arr(5) As Integer
        Dim i As Integer

        For i = 0 To arr.Length - 1
            arr(i) = i * i
        Next i

        For i = 0 To arr.Length - 1
            Console.WriteLine("arr(" & i & ") = " & arr(i))
        Next i
    End Sub
End Module

Program vypíše následující:

arr(0) = 0
arr(1) = 1
arr(2) = 4
arr(3) = 9
arr(4) = 16
arr(5) = 25

Každá dimenze pole má přidruženou délku. Délky dimenzí nejsou součástí typu pole, ale spíše jsou vytvořeny při vytvoření instance typu pole za běhu. Délka dimenze určuje platný rozsah indexů pro danou dimenzi: pro rozměr délky N, indexy mohou být v rozsahu od nuly do N-1. Pokud má dimenze nulovou délku, neexistují pro tuto dimenzi žádné platné indexy. Celkový počet prvků v matici je součin délky každé dimenze v matici. Pokud některá z dimenzí pole má délku nuly, znamená to, že matice je prázdná. Typ prvku pole může být libovolný typ.

Typy polí jsou určeny přidáním modifikátoru do existujícího názvu typu. Modifikátor se skládá z levé závorky, množiny nul nebo více čárk a pravé závorky. Změněný typ je typ prvku pole a počet dimenzí je počet čárek plus jedna. Pokud je zadán více než jeden modifikátor, je typ prvku pole pole pole. Modifikátory jsou čteny zleva doprava, přičemž nejkrajnější modifikátor je nejkrajnější pole. V příkladu

Module Test
    Dim arr As Integer(,)(,,)()
End Module

typ arr prvku je dvojrozměrné pole třírozměrných polí jednorozměrných polí .Integer

Proměnnou lze také deklarovat jako typ pole tak, že do názvu proměnné umístíte modifikátor typu pole nebo modifikátor inicializace velikosti pole. V takovém případě je typ prvku pole typem zadaným v deklaraci a dimenze pole jsou určeny modifikátorem názvu proměnné. Pro přehlednost není platné mít modifikátor typu pole pro název proměnné i název typu ve stejné deklaraci.

Následující příklad ukazuje řadu místních deklarací proměnných, které jako typ elementu používají typy Integer polí:

Module Test
    Sub Main()
        Dim a1() As Integer    ' Declares 1-dimensional array of integers.
        Dim a2(,) As Integer   ' Declares 2-dimensional array of integers.
        Dim a3(,,) As Integer  ' Declares 3-dimensional array of integers.

        Dim a4 As Integer()    ' Declares 1-dimensional array of integers.
        Dim a5 As Integer(,)   ' Declares 2-dimensional array of integers.
        Dim a6 As Integer(,,)  ' Declares 3-dimensional array of integers.

        ' Declare 1-dimensional array of 2-dimensional arrays of integers 
        Dim a7()(,) As Integer
        ' Declare 2-dimensional array of 1-dimensional arrays of integers.
        Dim a8(,)() As Integer

        Dim a9() As Integer() ' Not allowed.
    End Sub
End Module

Modifikátor názvu typu pole se rozšiřuje na všechny sady závorek, které následují. To znamená, že v situacích, kdy je za názvem typu povolena sada argumentů uzavřených v závorkách, není možné zadat argumenty pro název typu pole. Například:

Module Test
    Sub Main()
        ' This calls the Integer constructor.
        Dim x As New Integer(3)

        ' This declares a variable of Integer().
        Dim y As Integer()

        ' This gives an error.
        ' Array sizes can not be specified in a type name.
        Dim z As Integer()(3)
    End Sub
End Module

V posledním případě (3) se interpretuje jako součást názvu typu, nikoli jako sada argumentů konstruktoru.

Delegáti

Delegát je referenční typ, který odkazuje na Shared metodu typu nebo na metodu instance objektu.

DelegateDeclaration
    : Attributes? TypeModifier* 'Delegate' MethodSignature StatementTerminator
    ;

MethodSignature
    : SubSignature
    | FunctionSignature
    ;

Nejbližší ekvivalent delegáta v jiných jazycích je ukazatel funkce, ale zatímco ukazatel funkce může odkazovat pouze na funkce, delegát může odkazovat Shared na obě Shared metody i metody instance. V druhém případě delegát ukládá nejen odkaz na vstupní bod metody, ale také odkaz na instanci objektu, se kterou má vyvolat metodu.

Deklarace delegáta nemusí mít Handles klauzuli, Implements klauzuli, tělo metody nebo End konstruktor. Seznam parametrů deklarace delegáta nesmí obsahovat Optional ani ParamArray parametry. Doména přístupnosti návratového typu a typů parametrů musí být stejná jako nebo nadmnožina domény přístupnosti samotného delegáta.

Členové delegáta jsou členy zděděné z třídy System.Delegate. Delegát také definuje následující metody:

  • Konstruktor, který přebírá dva parametry, jeden typ Object a jeden typ System.IntPtr.

  • Metoda Invoke , která má stejný podpis jako delegát.

  • Metoda BeginInvoke , jejíž podpis je podpis delegáta, se třemi rozdíly. Nejprve se návratový typ změní na System.IAsyncResult. Za druhé se na konec seznamu parametrů přidají dva další parametry: první typ System.AsyncCallback a druhý typ Object. A nakonec se změní všechny ByRef parametry tak, aby ByValbyly .

  • Metoda EndInvoke , jejíž návratový typ je stejný jako delegát. Parametry metody jsou pouze parametry delegáta, které jsou ByRef přesně parametry, ve stejném pořadí, v jakém se vyskytují v podpisu delegáta. Kromě těchto parametrů je na konci seznamu parametrů další parametr typu System.IAsyncResult .

Při definování a používání delegátů existují tři kroky: deklarace, vytvoření instance a vyvolání.

Delegáti se deklarují pomocí syntaxe deklarace delegáta. Následující příklad deklaruje delegáta, SimpleDelegate který nepřijímá žádné argumenty:

Delegate Sub SimpleDelegate()

Další příklad vytvoří SimpleDelegate instanci a okamžitě ji zavolá:

Module Test
    Sub F()
        System.Console.WriteLine("Test.F")
    End Sub 

    Sub Main()
        Dim d As SimpleDelegate = AddressOf F
        d()
    End Sub 
End Module

Vytvoření instance delegáta pro metodu a následné okamžité volání prostřednictvím delegáta, protože by bylo jednodušší volat metodu přímo. Delegáti ukazují jejich užitečnost, když se používá anonymiza. Následující příklad ukazuje metodu MultiCallSimpleDelegate , která opakovaně volá instanci:

Sub MultiCall(d As SimpleDelegate, count As Integer)
    Dim i As Integer

    For i = 0 To count - 1
        d()
    Next i
End Sub

Není důležité pro metodu, MultiCall jaká je cílová metoda SimpleDelegate , jakou má tato metoda přístupnost, nebo jestli je Shared metoda nebo ne. Vše, co je důležité, je, že podpis cílové metody je kompatibilní s SimpleDelegate.

Částečné typy

Deklarace tříd a struktur mohou být částečné deklarace. Částečná deklarace může nebo nemusí plně popsat deklarovaný typ v rámci deklarace. Místo toho může být deklarace typu rozložena do více částečných deklarací v rámci programu; částečné typy nelze deklarovat přes hranice programu. Deklarace částečného Partial typu určuje modifikátor deklarace. Všechny další deklarace v programu pro typ se stejným plně kvalifikovaným názvem se sloučí společně s částečnou deklarací v době kompilace a vytvoří deklaraci jednoho typu. Například následující kód deklaruje jednu třídu Test se členy Test.C1 a Test.C2.

a.vb:

Public Partial Class Test
    Public Sub S1()
    End Sub
End Class

b.vb:

Public Class Test
    Public Sub S2()
    End Sub
End Class

Při kombinování částečných deklarací typu musí mít Partial alespoň jedna z deklarací modifikátor, jinak výsledky chyb v době kompilace.

Poznámka. I když je možné zadat Partial pouze jednu deklaraci mezi mnoha částečnými deklaracemi, je lepší ji zadat pro všechny částečné deklarace. V situaci, kdy je jedna částečná deklarace viditelná, ale jedna nebo více částečných deklarací jsou skrytá (například případ rozšíření kódu generovaného nástrojem), je přijatelné ponechat Partial modifikátor mimo viditelnou deklaraci, ale zadat ji u skrytých deklarací.

Pouze třídy a struktury lze deklarovat pomocí částečných deklarací. Při porovnávání částečných deklarací se považuje zarit typu: dvě třídy se stejným názvem, ale různá čísla parametrů typu se nepovažují za částečné deklarace stejného času. Částečné deklarace mohou určovat atributy, modifikátory tříd, Inherits příkaz nebo Implements příkaz. V době kompilace jsou všechny části částečných deklarací sloučeny a použity jako součást deklarace typu. Pokud existují nějaké konflikty mezi atributy, modifikátory, základy, rozhraní nebo členy typu, výsledky chyb v době kompilace. Například:

Public Partial Class Test1
    Implements IDisposable
End Class

Class Test1
    Inherits Object
    Implements IComparable
End Class

Public Partial Class Test2
End Class

Private Partial Class Test2
End Class

Předchozí příklad deklaruje typ Test1 , který je Public, dědí z Object a implementuje System.IDisposable a System.IComparable. Částečné deklarace Test2 způsobí chybu v době kompilace, protože jedna z deklarací říká, že je Public a Test2 další říká, že Test2 je Private.

Částečné typy s parametry typu mohou deklarovat omezení a odchylku parametrů typu, ale omezení a odchylky od každé částečné deklarace se musí shodovat. Omezení a rozptyl jsou tedy speciální v tom, že se automaticky nezkombinují jako jiné modifikátory:

Partial Public Class List(Of T As IEnumerable)
End Class

' Error: Constraints on T don't match
Class List(Of T As IComparable)
End Class

Skutečnost, že typ je deklarován pomocí více částečných deklarací, nemá vliv na pravidla vyhledávání názvů v rámci typu. V důsledku toho může částečná deklarace typu používat členy deklarované v jiných deklarací částečného typu nebo může implementovat metody v rozhraních deklarovaných v jiných deklarací částečného typu. Například:

Public Partial Class Test1
    Implements IDisposable

    Private IsDisposed As Boolean = False
End Class

Class Test1
    Private Sub Dispose() Implements IDisposable.Dispose
        If Not IsDisposed Then
            ...
        End If
    End Sub
End Class

Vnořené typy můžou mít také částečné deklarace. Například:

Public Partial Class Test
    Public Partial Class NestedTest
        Public Sub S1()
        End Sub
    End Class
End Class

Public Partial Class Test
    Public Partial Class NestedTest
        Public Sub S2()
        End Sub
    End Class
End Class

Inicializátory v rámci částečné deklarace budou stále prováděny v pořadí deklarace; Neexistuje však žádné zaručené pořadí provádění inicializátorů, ke kterým dochází v samostatných částečných deklaracích.

Vytvořené typy

Deklarace obecného typu sama o sobě neoznačí typ. Místo toho lze deklaraci obecného typu použít jako "podrobný plán" k vytvoření mnoha různých typů pomocí argumentů typu. Obecný typ s použitými argumenty typu se nazývá konstruovaný typ. Argumenty typu v konstruovaného typu musí vždy splňovat omezení na parametry typu, které odpovídají.

Název typu může identifikovat vytvořený typ, i když přímo nezadává parametry typu. K tomu může dojít v případě, že je typ vnořený v deklaraci obecné třídy a typ instance obsahující deklarace se implicitně používá pro vyhledávání názvů:

Class Outer(Of T) 
    Public Class Inner 
    End Class

    ' Type of i is the constructed type Outer(Of T).Inner
    Public i As Inner 
End Class

Konstruovaný typ C(Of T1,...,Tn) je přístupný, pokud jsou obecný typ a všechny argumenty typu přístupné. Pokud je například obecný typ CPublic a všechny argumenty T1,...,Tn typu jsou Public, pak vytvořený typ je Public. Pokud je Privatevšak název typu nebo jeden z argumentů typu, je přístupnost vytvořeného typu Private. Pokud je jeden typ argumentu vytvořeného typu Protected a jiný typ argument je Friend, pak je konstruovaný typ přístupný pouze ve třídě a jeho podtřídy v tomto sestavení nebo jakékoli sestavení, které byl udělen Friend přístup. Jinými slovy, doména přístupnosti pro konstruovaný typ je průnik domén přístupnosti jejích základních částí.

Poznámka. Skutečnost, že doména přístupnosti vytvořeného typu je průnikem jeho součástí, má zajímavý vedlejší účinek definování nové úrovně přístupnosti. Vytvořený typ, který obsahuje prvek, který je Protected a prvek, který je Friend přístupný pouze v kontextech, které mají přístup k oběmaFriendčlenůmProtected . Neexistuje však způsob, jak vyjádřit tuto úroveň přístupnosti v jazyce, protože přístupnost Protected Friend znamená, že k entitě lze přistupovat v kontextu, ke kterému má přístup buďFriendneboProtected členové.

Základní implementovaná rozhraní a členy konstruovaných typů jsou určeny nahrazením zadaných argumentů typu pro každý výskyt parametru typu v obecném typu.

Otevřené typy a uzavřené typy

Konstruovaný typ, pro kterého jeden nebo více argumentů typu jsou parametry typu obsahující typ nebo metoda se nazývá otevřený typ. Důvodem je to, že některé parametry typu typu stále nejsou známé, takže skutečný tvar typu ještě není plně známý. Naproti tomu obecný typ, jehož argumenty typu jsou všechny parametry bez typu, se nazývá uzavřený typ. Tvar uzavřeného typu je vždy plně známý. Například:

Class Base(Of T, V)
End Class

Class Derived(Of V)
    Inherits Base(Of Integer, V)
End Class

Class MoreDerived
    Inherits Derived(Of Double)
End Class

Vytvořený typ je otevřený typ Base(Of Integer, V) , protože ačkoli byl zadán parametr T typu, U byl zadán další parametr typu. Proto úplný tvar typu ještě není znám. Vytvořený typ je však uzavřený typ Derived(Of Double), protože byly zadány všechny parametry typu v hierarchii dědičnosti.

Otevřené typy jsou definovány takto:

  • Parametr typu je otevřený typ.

  • Typ pole je otevřený typ, pokud je jeho typ prvku otevřený typ.

  • Konstruovaný typ je otevřený typ, pokud jeden nebo více argumentů jeho typu je otevřený typ.

  • Uzavřený typ je typ, který není otevřeným typem.

Vzhledem k tomu, že vstupní bod programu nemůže být v obecném typu, budou uzavřeny všechny typy použité za běhu.

Speciální typy

Rozhraní .NET Framework obsahuje řadu tříd, které jsou zpracovávány speciálně rozhraním .NET Framework a jazykem Visual Basic:

Typ System.Void, který představuje typ void v rozhraní .NET Framework, lze přímo odkazovat pouze ve GetType výrazech.

Typy System.RuntimeArgumentHandleSystem.ArgIterator a System.TypedReference všechny můžou obsahovat ukazatele do zásobníku, takže se nemohou objevit v haldě rozhraní .NET Framework. Nelze je proto použít jako typy prvků pole, návratové typy, typy polí, obecné argumenty typu, typy s možnou hodnotou null, ByRef typy parametrů, typ hodnoty převedené na Object nebo System.ValueType, cíl volání členů Object instance nebo System.ValueTypenebo zvednut do uzavření.