Visual Basic 中類型的兩個基本類別是 實值型 別和 參考型別。 基本類型(字串除外)、列舉和結構都是實值型別。 類別、字串、標準模組、介面、陣列和委派都是參考型別。
每個類型都有 預設值,這是在初始化時指派給該類型變數的值。
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?
;
實值型別和參考型別
雖然實值類型和參考型別在宣告語法和使用方式方面可能很類似,但其語意是不同的。
參考類型會儲存在運行時間堆積上;它們只能透過該記憶體的參考來存取。 由於參考型別一律會透過參考存取,因此其存留期是由 .NET Framework 管理。 追蹤特定實例的未處理參考,而且只有在不再保留任何參考時,才會終結實例。 參考類型的變數包含該型別值的參考、衍生型別的值或 Null 值。 Null 值不參考任何值;除了指派 Null 值之外,無法執行任何動作。 對參考型別變數的指派會建立參考的複本,而不是參考值的複本。 對於參考類型的變數,預設值為 Null 值。
實值型別會直接儲存在堆疊上,無論是在陣列內還是另一種類型內;只能直接存取其記憶體。 因為實值型別會直接儲存在變數內,因此其存留期取決於包含它們的變數存留期。 當包含實值型別實例的位置終結時,實值型別實例也會終結。 實值型別一律會直接存取;無法建立實值型別的參考。 禁止這類參考,使得無法參考已終結的值類別實例。 因為實值型別一律 NotInheritable為 ,實值型別的變數一律包含該類型的值。 因此,實值型別的值不可以是 Null 值,也不能參考衍生型別的物件。 指派給實值型別的變數會建立所指派值的複本。 對於實值型別的變數,預設值是將類型的每個變數成員初始化為其預設值的結果。
下列範例顯示參考型別與實值型別之間的差異:
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
程式輸出為:
Values: 0, 123
Refs: 123, 123
局部變數的指派不會影響局部變數 val2 ,因為這兩個局部變數 val1 都是實值類型(類型 Integer),而實值型別的每個局部變數都有自己的記憶體。 相反地,指派ref2.Value = 123;會影響 和 ref2 參考的物件ref1。
關於 .NET Framework 類型系統的一件事是,即使結構、列舉型別和基本型別(除外 String)都是實值型別,但它們都繼承自參考型別。 結構和基本型別繼承自 參考型 System.ValueType別 ,其繼承自 Object。 列舉型別繼承自 參考型 System.Enum別 ,其繼承自 System.ValueType。
可為 Null 的數值類型
對於實值型別, ? 修飾詞可以新增至類型名稱,以表示該類型的 可為 Null 版本。
NullableTypeName
: NonArrayTypeName '?'
;
NullableNameModifier
: '?'
;
可為 Null 的實值類型可以包含與類型不可為 Null 版本以及 Null 值相同的值。 因此,針對可為 Null 的實值型別,指派 Nothing 給型別的變數會將變數的值設定為 Null 值,而不是實值型別的零值。 例如:
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)
變數也可以藉由將可為 Null 的類型修飾詞放在變數名稱上,宣告為可為 Null 的實值類型。 為了清楚起見,在變數名稱和相同宣告中的型別名稱上都有可為 Null 的類型修飾詞無效。 由於可為 Null 的型別是使用 型 System.Nullable(Of T)別實作,因此類型 T? 與型 System.Nullable(Of T)別同義,而且兩個名稱可以交替使用。
?修飾詞不能放在已經可為 Null 的類型上,因此無法宣告類型Integer??或 System.Nullable(Of Integer)?。
可為 Null 的實值型T?別具有 的成員System.Nullable(Of T),以及從基礎型T別提升到 型別T?的任何運算符或轉換。 從基礎型別解除複製運算符和轉換,在大部分情況下,會將可為 Null 的實值型別取代為不可為 Null 的實值型別。 這可讓許多套用至 T 的相同轉換與作業套用至 T? 。
介面實作
結構和類別宣告可以宣告它們透過一或多個 Implements 子句實作一組介面類型。
TypeImplementsClause
: 'Implements' TypeImplements StatementTerminator
;
TypeImplements
: NonArrayTypeName ( Comma NonArrayTypeName )*
;
子句中指定的 Implements 所有型別都必須是介面,而且型別必須實作介面的所有成員。 例如:
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
實作介面的類型也會隱含實作介面的所有基底介面。 即使類型未明確列出 子句中的所有 Implements 基底介面,也是如此。 在這裡範例中,結構 TextBox 會同時實作 IControl 和 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
宣告型別會在和 本身實作介面,並不會在型別的宣告空間中宣告任何專案。 因此,使用相同名稱的方法實作兩個介面是有效的。
型別無法自行實作類型參數,雖然它可能涉及範圍中的類型參數。
Class C1(Of V)
Implements V ' Error, can't implement type parameter directly
Implements IEnumerable(Of V) ' OK, not directly implementing
...
End Class
泛型介面可以使用不同的類型自變數多次實作。 不過,如果提供的型別參數(不論類型條件約束為何)可能會與該介面的另一個實作重疊,泛型型別就無法使用型別參數實作泛型介面。 例如:
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
基本類型
基本 類型 是透過關鍵詞來識別,這些關鍵詞是命名空間中預先定義型別的 System 別名。 基本類型與別名的類型完全不區分:撰寫保留字 Byte 與寫入 System.Byte完全相同。 基本類型也稱為 內建型別。
PrimitiveTypeName
: NumericTypeName
| 'Boolean'
| 'Date'
| 'Char'
| 'String'
;
NumericTypeName
: IntegralTypeName
| FloatingPointTypeName
| 'Decimal'
;
IntegralTypeName
: 'Byte' | 'SByte' | 'UShort' | 'Short' | 'UInteger'
| 'Integer' | 'ULong' | 'Long'
;
FloatingPointTypeName
: 'Single' | 'Double'
;
因為基本類型別名為一般類型,因此每個基本類型都有成員。 例如, Integer 在中 System.Int32宣告成員。 常值可以視為其對應類型的實例。
基本類型與其他結構類型不同,因為它們允許某些額外的作業:
基本類型允許藉由撰寫常值來建立值。 例如,
123I是類型的Integer常值。可以宣告基本類型的常數。
當表達式的作數都是基本類型常數時,編譯程式可以在編譯時期評估表達式。 這類表達式稱為常數表達式。
Visual Basic 定義下列基本類型:
整數值類型
Byte(1 位元組無符號整數)、(1 位元組帶正負號整數)、UShortSByte(2 位元組無符號整數)、(2UInteger位元組帶正負號整數)、Short(4 位元組無符號整數)、(4ULong位元組帶正負號整數)、(8 位元組無Integer符號整數)和Long(8 位元組帶正負號整數)。 這些類型分別對應至System.Byte、System.SByte、System.Int16System.UInt16System.UInt32System.Int32System.UInt64和 。System.Int64整數型別的預設值相當於常值0。浮點實值型
Single別 (4 位元組浮點) 和Double(8 位元組浮點)。 這些類型分別對應至System.Single和System.Double。 浮點型別的預設值相當於常值0。對應
Decimal至System.Decimal的型別 (16 位元組十進位值)。 decimal 的預設值相當於常值0D。實
Boolean值型別,代表真值,通常是關係型或邏輯運算的結果。 常值的類型為System.Boolean。 型別的Boolean預設值相當於常值False。實
Date值型別,表示日期和/或時間,並對應至System.DateTime。 型別的Date預設值相當於常值# 01/01/0001 12:00:00AM #。實
Char值型別,表示單一 Unicode 字元,並對應至System.Char。 型別的Char預設值相當於常數表示式ChrW(0)。參考
String型別,表示 Unicode 字元序列,並對應至System.String。 型別String的預設值為 Null 值。
列舉項目
列舉 是繼承自 System.Enum 的實值型別,並以符號方式表示其中一個基本整數型別的一組值。
EnumDeclaration
: Attributes? TypeModifier* 'Enum' Identifier
( 'As' NonArrayTypeName )? StatementTerminator
EnumMemberDeclaration+
'End' 'Enum' StatementTerminator
;
對於列舉型 E別,預設值是表達式 CType(0, E)所產生的值。
列舉的基礎型別必須是整數型別,可以代表列舉中定義的所有列舉值。 如果指定了基礎型別,它必須是Byte命名空間中的System其中一個對應型別、UShortSByte、ULongIntegerUIntegerShort、 Long或其中一個。 如果未明確指定基礎類型,則預設值為 Integer。
下列範例會宣告具有 基礎型別的 Long列舉:
Enum Color As Long
Red
Green
Blue
End Enum
開發人員可以選擇使用 的基礎型 Long別 ,如範例所示,啟用 在範圍內 Long使用的值,但不在的範圍中 Integer,或保留這個選項供未來使用。
列舉成員
列舉的成員是列舉中宣告的列舉值,以及繼承自 類別 System.Enum的成員。
列舉成員的範圍是列舉宣告主體。 這表示在列舉宣告之外,列舉成員必須一律限定(除非類型是透過命名空間匯入特別匯入命名空間)。
列舉成員宣告的宣告順序在省略常數表達式值時很重要。 列舉成員隱含地具有 Public 存取權;列舉成員宣告上不允許任何存取修飾詞。
EnumMemberDeclaration
: Attributes? Identifier ( Equals ConstantExpression )? StatementTerminator
;
列舉值
列舉成員清單中的列舉值會宣告為類型為基礎列舉型別的常數,而且可以在需要常數的位置出現。 具有的列舉成員定義 = 會為相關聯成員提供常數表達式所指示的值。 常數表達式必須評估為可隱含轉換成基礎型別的整數型別,而且必須位於可由基礎型別表示的值範圍內。 下列範例發生錯誤,因為 常數值 1.5、 2.3和 3.3 無法隱含轉換成具有嚴格語意的基礎整數類型 Long 。
Option Strict On
Enum Color As Long
Red = 1.5
Green = 2.3
Blue = 3.3
End Enum
多個列舉成員可以共用相同的相關聯值,如下所示:
Enum Color
Red
Green
Blue
Max = Blue
End Enum
此範例顯示具有兩個列舉成員 -- Blue 和 Max -- 的列舉,其相關聯的值相同。
如果列舉中的第一個列舉值定義沒有初始化運算式,則對應常數的值是 0。 沒有初始化表達式的列舉值定義會提供列舉值,其值會藉由 增加先前列舉值的值來 1取得。 這個增加的值必須位於基礎類型可以表示的值範圍內。
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
上述範例會列印列舉值及其相關聯的值。 輸出如下:
Red = 0
Green = 10
Blue = 11
值的原因如下:
列舉值
Red會自動指派值0(因為它沒有初始化表達式,而且是第一個列舉值成員)。列舉值
Green會明確指定值10。列舉值
Blue會自動指派大於文字前面之列舉值的值。
常數表達式不得直接或間接使用其本身相關列舉值的值(也就是說,不允許常數表達式中的迴圈性)。 下列範例無效,因為和 B 的A宣告是迴圈的。
Enum Circular
A = B
B
End Enum
A 相 B 依於明確,並 B 隱含相依 A 。
班級
類別是數據結構,可能包含數據成員(常數、變數和事件)、函式成員(方法、屬性、索引器、運算元和建構函式),以及巢狀類型。 類別是參考型別。
ClassDeclaration
: Attributes? ClassModifier* 'Class' Identifier TypeParameterList? StatementTerminator
ClassBase?
TypeImplementsClause*
ClassMemberDeclaration*
'End' 'Class' StatementTerminator
;
ClassModifier
: TypeModifier
| 'MustInherit'
| 'NotInheritable'
| 'Partial'
;
下列範例顯示包含每一種成員的類別:
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
下列範例顯示這些成員的用法:
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
有兩個類別特定的修飾詞和 MustInheritNotInheritable。 指定兩者都無效。
類別基底規格
類別宣告可能包含定義類別直接基底類型的基底類型規格。
ClassBase
: 'Inherits' NonArrayTypeName StatementTerminator
;
如果類別宣告沒有明確的基底類型,則直接基底類型是隱含 Object的 。 例如:
Class Base
End Class
Class Derived
Inherits Base
End Class
基底類型本身不能是類型參數,雖然它可能涉及範圍中的類型參數。
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
類別只能衍生自 Object 和類別。 類別衍生自 System.ValueType、、 System.MulticastDelegateSystem.EnumSystem.Array或 System.Delegate無效。 泛型類別無法衍生自 System.Attribute 或衍生自它的類別。
每個類別都有一個直接基類,而且禁止衍生中的迴圈。 無法衍生自 類別 NotInheritable ,而且基類的輔助功能定義域必須與 類別本身的輔助功能定義域或超集相同。
類別成員
類別的成員包含其類別成員宣告所引進的成員,以及繼承自其直接基類的成員。
ClassMemberDeclaration
: NonModuleDeclaration
| EventMemberDeclaration
| VariableMemberDeclaration
| ConstantMemberDeclaration
| MethodMemberDeclaration
| PropertyMemberDeclaration
| ConstructorMemberDeclaration
| OperatorDeclaration
;
類別成員宣告可能有 Public、、ProtectedFriend、 Protected Friend或 Private 存取權。 當類別成員宣告不包含存取修飾詞時,除非宣告是變數宣告,否則宣告預設 Public 為存取;在此情況下,它會預設為 Private 存取。
類別成員的範圍是成員宣告所在的類別主體,加上該類別的條件約束清單(如果是泛型且具有條件約束)。 如果成員具有 Friend 存取權,其範圍會延伸至相同程式中任何衍生類別的類別主體,或已獲得 Friend 存取權的任何元件,如果成員具有 Public、 Protected或 Protected Friend 存取權,其範圍就會延伸到任何程式中任何衍生類別的類別主體。
結構體系
結構 是繼承自 System.ValueType的實值型別。 結構類似於 類別,其代表可包含數據成員和函式成員的數據結構。 不過,不同於類別,結構不需要堆積配置。
StructureDeclaration
: Attributes? StructureModifier* 'Structure' Identifier
TypeParameterList? StatementTerminator
TypeImplementsClause*
StructMemberDeclaration*
'End' 'Structure' StatementTerminator
;
StructureModifier
: TypeModifier
| 'Partial'
;
在類別的情況下,兩個變數可以參考相同的物件,因此一個變數上的作業可能會影響另一個變數所參考的物件。 使用 結構時,變數各有自己的非Shared 數據複本,因此無法讓一個上的作業影響另一個數據,如下列範例所示:
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
假設上述宣告,下列程式代碼會輸出 值 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
指派 a 給 b 時會建立值的複本,因此 b 不會受到指派給 a.x 的影響。 若 Point 被宣告為類別,輸出將為 100,因為 a 和 b 将參考相同的物件。
結構成員
結構的成員是其結構成員宣告所引進的成員,以及繼承自 System.ValueType的成員。
StructMemberDeclaration
: NonModuleDeclaration
| VariableMemberDeclaration
| ConstantMemberDeclaration
| EventMemberDeclaration
| MethodMemberDeclaration
| PropertyMemberDeclaration
| ConstructorMemberDeclaration
| OperatorDeclaration
;
每個結構都會隱含地有一個 Public 無參數實例建構函式,其會產生結構的預設值。 因此,結構類型宣告不可能宣告無參數實例建構函式。 不過,結構類型允許宣告 參數化 實例建構函式,如下列範例所示:
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
在上述宣告中,下列語句都會使用 和 y 初始化為零來建立 。Pointx
Dim p1 As Point = New Point()
Dim p2 As Point = New Point(0, 0)
因為結構會直接包含其域值(而不是參考這些值),所以結構不能包含直接或間接參考本身的欄位。 例如,下列程式代碼無效:
Structure S1
Dim f1 As S2
End Structure
Structure S2
' This would require S1 to contain itself.
Dim f1 As S1
End Structure
一般而言,結構成員宣告可能只有、 或 存取權,但覆寫繼承自 ProtectedProtected FriendObject的成員時,也可以使用存取權。PrivateFriendPublic 當結構成員宣告不包含存取修飾詞時,宣告預設為 Public 存取。 結構所宣告的成員範圍是宣告發生的結構主體,加上該結構的條件約束(如果是泛型且具有條件約束)。
標準模組
標準模組是一種類型,其成員會隱含Shared且範圍限定於標準模組包含命名空間的宣告空間,而不只是限定於標準模組宣告本身。 標準模組可能永遠不會具現化。 宣告標準模組類型的變數時發生錯誤。
ModuleDeclaration
: Attributes? TypeModifier* 'Module' Identifier StatementTerminator
ModuleMemberDeclaration*
'End' 'Module' StatementTerminator
;
標準模組的成員有兩個完整名稱,一個沒有標準模組名稱和一個具有標準模組名稱。 命名空間中的多個標準模組可以定義具有特定名稱的成員;其中一個模組外部名稱的不限定參考模棱兩可。 例如:
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
模組只能在命名空間中宣告,而且不能以巢狀方式在另一種類型中。 標準模組可能不會實作介面,它們隱含衍生自 Object,而且只有 Shared 建構函式。
標準模組成員
標準模組的成員是其成員宣告所引進的成員,以及繼承自 Object的成員。 除了實例建構函式之外,標準模組可能具有任何類型的成員。 所有標準模組類型成員都是隱含 Shared的 。
ModuleMemberDeclaration
: NonModuleDeclaration
| VariableMemberDeclaration
| ConstantMemberDeclaration
| EventMemberDeclaration
| MethodMemberDeclaration
| PropertyMemberDeclaration
| ConstructorMemberDeclaration
;
標準模組成員宣告通常只能有、 或 存取權,但覆寫繼承自 ObjectProtected 的成員時,可以指定 和 Protected Friend 存取修飾詞。PrivateFriendPublic 當標準模組成員宣告不包含存取修飾詞時,除非它是預設存取的變數,否則宣告 Public 預設為 Private 存取。
如先前所述,標準模組成員的範圍是包含標準模組宣告的宣告。 繼承自 Object 的成員不會包含在此特殊範圍中;這些成員沒有範圍,而且必須一律以模組的名稱限定。 如果成員具有 Friend 存取權,其範圍只會延伸至已授 Friend 與存取權之相同程式或元件中宣告的命名空間成員。
介面
介面 是其他類型的參考型別,可保證它們支援某些方法。 介面永遠不會直接建立,而且沒有實際表示法 -- 其他類型必須轉換成介面類型。 介面會定義合約。 實作介面的類別或結構必須遵守其合約。
InterfaceDeclaration
: Attributes? TypeModifier* 'Interface' Identifier
TypeParameterList? StatementTerminator
InterfaceBase*
InterfaceMemberDeclaration*
'End' 'Interface' StatementTerminator
;
下列範例顯示包含預設屬性 Item、事件 E、方法 F及屬性 P的介面:
Interface IExample
Default Property Item(index As Integer) As String
Event E()
Sub F(value As Integer)
Property P() As String
End Interface
介面可能會採用多個繼承。 在下列範例中,介面 IComboBox 繼承自 ITextBox 和 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
類別和結構可以實作多個介面。 在下列範例中,類別 EditBox 衍生自 類別 Control ,並同時實作 IControl 和 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
介面繼承
介面的基底介面是明確的基底介面及其基底介面。 換句話說,基底介面的集合是對明確基底介面、其明確基底介面等等的完整可傳遞閉包。 如果介面宣告沒有明確的介面基底,則類型沒有基底介面 -- 介面不會繼承自 Object (雖然它們確實有擴大的轉換至 Object)。
InterfaceBase
: 'Inherits' InterfaceBases StatementTerminator
;
InterfaceBases
: NonArrayTypeName ( Comma NonArrayTypeName )*
;
在下列範例中,的基底介面 IComboBox 為 IControl、 ITextBox和 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
介面會繼承其基底介面的所有成員。 換句話說,IComboBox上述介面會繼承成員SetText、SetItems以及Paint。
實作介面的類別或結構也會隱含實作介面的所有基底介面。
如果介面在基底介面的可轉移關閉中出現一次以上,它只會將其成員貢獻給衍生介面一次。 實作衍生介面的類型只需要實作相乘定義基底介面的方法一次。 在下列範例中,Paint即使 類別實作 和 IControl,也只需要實作IComboBox一次。
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
子 Inherits 句對其他 Inherits 子句沒有任何作用。 在下列範例中, IDerived 必須將 的名稱 INested 限定為 IBase。
Interface IBase
Interface INested
Sub Nested()
End Interface
Sub Base()
End Interface
Interface IDerived
Inherits IBase, INested ' Error: Must specify IBase.INested.
End Interface
基底介面的輔助功能定義域必須與介面本身的輔助功能定義域或超集相同。
介面成員
介面的成員包含其成員宣告所引進的成員,以及繼承自其基底介面的成員。
InterfaceMemberDeclaration
: NonModuleDeclaration
| InterfaceEventMemberDeclaration
| InterfaceMethodMemberDeclaration
| InterfacePropertyMemberDeclaration
;
雖然介面不會從 Object繼承成員,因為實作介面的每個類別或結構都會繼承自 Object, Object包括擴充方法的成員會被視為介面的成員,而且可以直接在介面上呼叫,而不需要轉換成 Object。 例如:
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
與隱含陰影Object成員成員同名的Object介面成員。 只有巢狀類型、方法、屬性和事件可能是介面的成員。 方法和屬性可能沒有主體。 介面成員是隱含的 Public ,而且可能不會指定存取修飾詞。 介面中宣告的成員範圍是宣告發生所在的介面主體,加上該介面的條件約束清單(如果是泛型且具有條件約束)。
陣列
數位是參考型別,其中包含透過以一對一方式對應之索引存取的變數,以及陣列中變數的順序。 陣列中包含的變數,也稱為數位的 元素 ,都必須是相同的類型,而且這個類型稱為數位的 元素類型 。
ArrayTypeName
: NonArrayTypeName ArrayTypeModifiers
;
ArrayTypeModifiers
: ArrayTypeModifier+
;
ArrayTypeModifier
: OpenParenthesis RankList? CloseParenthesis
;
RankList
: Comma*
;
ArrayNameModifier
: ArrayTypeModifiers
| ArraySizeInitializationModifier
;
當建立陣列實例時,陣列的元素就會存在,而且當陣列實例終結時就不再存在。 數位的每個項目都會初始化為其類型的預設值。 此類型 System.Array 是所有數位類型的基底類型,而且可能不會具現化。 每個數位類型都會繼承型別所 System.Array 宣告的成員,並且可轉換成它 (和 Object)。 具有 元素T的一維陣列類型也會實作 介面System.Collections.Generic.IList(Of T)和 IReadOnlyList(Of T);如果 T 是參考型別,則陣列類型也會針對IList(Of U)任何U具有從 T擴大參考轉換的 實作 和 IReadOnlyList(Of U) 。
陣列有一個 排名 ,可決定與每個數位專案相關聯的索引數目。 陣列的排名決定陣列的 維度 數目。 例如,排名為一的陣列稱為單一維度陣列,且排名大於一的陣列稱為多維度陣列。
下列範例會建立整數值的一維陣列、初始化陣列元素,然後列印出每個元素:
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
程式會輸出下列專案:
arr(0) = 0
arr(1) = 1
arr(2) = 4
arr(3) = 9
arr(4) = 16
arr(5) = 25
數位的每個維度都有相關聯的長度。 維度長度不是數位類型的一部分,而是在運行時間建立數位類型的實例時建立。 維度的長度決定該維度的有效索引範圍:對於長度 N的維度,索引的範圍可以從零到 N-1。 如果維度的長度為零,該維度沒有有效的索引。 陣列中的元素總數是陣列中每個維度長度的乘積。 如果陣列的任何維度長度為零,則表示陣列是空的。 陣列的元素類型可以是任何類型。
數位型態是藉由將修飾詞新增至現有的類型名稱來指定。 修飾詞包含左括弧、一組零或多個逗號,以及右括弧。 修改的類型是陣列的元素類型,而維度的數目是逗號加上一個。 如果指定了多個修飾詞,則數位的元素類型是陣列。 修飾詞會由左至右讀取,最左邊的修飾詞是最外層的陣列。 在範例中
Module Test
Dim arr As Integer(,)(,,)()
End Module
的項目類型 arr 是的三維陣列的二維陣列 Integer。
變數也可以藉由將數位類型修飾詞或陣列大小的初始化修飾詞放在變數名稱上,宣告為數位類型。 在此情況下,陣列元素類型是宣告中指定的類型,而陣列維度是由變數名稱修飾詞所決定。 為了清楚起見,在變數名稱和相同宣告中的類型名稱上都有數位類型修飾詞無效。
下列範例顯示各種局部變數宣告,這些宣告使用數位類型搭配 Integer 作為項目類型:
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
陣列類型名稱修飾詞會延伸至其後面的所有括弧集合。 這表示在類型名稱之後允許括在括弧內的一組自變數時,無法指定數位類型名稱的自變數。 例如:
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
在最後一個案例中, (3) 會解譯為類型名稱的一部分,而不是一組建構函式自變數。
代表們
委派是參考型別或對象實例方法的參考型Shared別。
DelegateDeclaration
: Attributes? TypeModifier* 'Delegate' MethodSignature StatementTerminator
;
MethodSignature
: SubSignature
| FunctionSignature
;
其他語言中委派最接近的對等專案是函式指標,但函式指標只能參考函式,委派可以同時參考 SharedShared 和 實例方法。 在後者的情況下,委派不僅會儲存方法進入點的參考,也會儲存用來叫用方法之物件實例的參考。
委派宣告可能沒有 Handles 子句、 Implements 子句、方法主體或 End 建構。 委派宣告的參數清單不得包含 Optional 或 ParamArray 參數。 傳回型別和參數型別的輔助功能定義域必須與委派本身的輔助功能定義域或超集相同。
委派的成員是繼承自 類別 System.Delegate的成員。 委派也會定義下列方法:
採用兩個參數的建構函式,其中一個是 型
Object別,另一個型別System.IntPtr為 。Invoke與委派具有相同簽章的方法。BeginInvoke簽章為委派簽章的方法,有三個差異。 首先,傳回型別會變更為System.IAsyncResult。 其次,將另外兩個參數新增至參數列表的結尾:第一個型System.AsyncCallback別和第二個 型別Object。 最後,所有ByRef參數都會變更為ByVal。傳
EndInvoke回型別與委派相同的方法。 方法的參數只是與委派簽章中發生的順序相同之參數的ByRef委派參數。 除了這些參數之外,參數清單結尾還有類型System.IAsyncResult的額外參數。
定義和使用委派有三個步驟:宣告、具現化和調用。
委派是使用委派宣告語法來宣告。 下列範例會宣告名為 SimpleDelegate 的委派,該委派不接受任何自變數:
Delegate Sub SimpleDelegate()
下一個 SimpleDelegate 範例會建立 實例,然後立即呼叫它:
Module Test
Sub F()
System.Console.WriteLine("Test.F")
End Sub
Sub Main()
Dim d As SimpleDelegate = AddressOf F
d()
End Sub
End Module
具現化方法的委派並立即透過委派呼叫沒有太多意義,因為直接呼叫 方法會比較簡單。 當使用匿名時,委派會顯示其實用性。 下一個 MultiCall 範例顯示會重複呼叫 SimpleDelegate 實例的方法:
Sub MultiCall(d As SimpleDelegate, count As Integer)
Dim i As Integer
For i = 0 To count - 1
d()
Next i
End Sub
MultiCall此方法的目標方法SimpleDelegate、這個方法的輔助功能,還是方法是否重要Shared。 重要的是目標方法的簽章與 SimpleDelegate相容。
部分型別
類別和結構宣告可以是 部分 宣告。 部分宣告不一定能完整描述宣告內的宣告類型。 相反地,型別的宣告可能會分散到程式中的多個部分宣告;部分類型無法跨程式界限宣告。 部分類型宣告會 Partial 指定宣告上的修飾詞。 然後,具有相同完整名稱之型別之程式中的任何其他宣告,都會在編譯階段與部分宣告合併,以形成單一類型宣告。 例如,下列程式代碼會宣告具有成員Test.C1和Test.C2的單一類別Test。
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
結合部分型別宣告時,至少有一個宣告必須有 Partial 修飾詞,否則會產生編譯時期的錯誤結果。
注意。 雖然可以在許多部分宣告中只指定 Partial 一個宣告,但最好是在所有部分宣告上指定它。 在一個部分宣告可見但隱藏一或多個部分宣告的情況下(例如擴充工具產生的程式代碼的情況),可以接受讓修飾詞離開 Partial 可見宣告,但在隱藏宣告上指定。
只有類別和結構可以使用部分宣告來宣告。 將部分宣告比對在一起時,會考慮類型的arity:兩個具有相同名稱但類型參數數目不同的類別不會被視為相同時間的部分宣告。 部分宣告可以指定屬性、類別修飾詞、 Inherits 語句或 Implements 語句。 在編譯時期,部分宣告的所有部分都會結合在一起,並做為類型宣告的一部分。 如果屬性、修飾詞、基底、介面或類型成員之間有任何衝突,則編譯時期錯誤結果。 例如:
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
上一個範例會宣告 類型 Test1 ,其 Public繼承自 Object 並實作 System.IDisposable 和 System.IComparable。 的部分Test2宣告將會導致編譯時期錯誤,因為其中一個宣告表示Test2,也就是說Public,另一個宣告則Test2表示 。Private
具有類型參數的部分類型可以宣告類型參數的條件約束和變數,但每個部分宣告的條件約束和變異數必須相符。 因此,條件約束和變異數特別,因為它們不會像其他修飾詞一樣自動合併:
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
使用多個部分宣告宣告類型的事實不會影響類型內的名稱查閱規則。 因此,部分型別宣告可以使用在其他部分類型宣告中宣告的成員,或可以在其他部分類型宣告中宣告的介面上實作方法。 例如:
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
巢狀類型也可以有部分宣告。 例如:
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
部分宣告內的初始化表達式仍會以宣告順序執行;不過,初始化表達式的執行順序並不保證會在個別的部分宣告中發生。
建構的類型
泛型型別宣告本身並不代表型別。 相反地,泛型型別宣告可以做為「藍圖」,藉由套用類型自變數來形成許多不同類型的類型。 已套用類型自變數的泛型型別稱為 建構型別。 建構型別中的型別自變數必須一律滿足它們所符合之類型參數的條件約束。
即使類型名稱未直接指定類型參數,類型名稱還是可能會識別已建構的類型。 當類型巢狀於泛型類別宣告內,且包含宣告的實例類型隱含用於名稱查閱時,就可能發生此問題:
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
當泛型型別和所有型別自變數都可供存取時,可存取建構 C(Of T1,...,Tn) 型別。 例如,如果泛型型 C 別是 Public ,而且所有型別自變數 T1,...,Tn 都是 Public,則建構的類型為 Public。 不過,如果型別名稱或其中一個型別自變數為 Private,則建構型別的輔助功能為 Private。 如果建構型別的其中一個型別自變數是 Protected ,而另一個型別自變數是 Friend,則建構型別只能在類別及其子類別中存取這個元件,或已取得 Friend 存取權的任何元件。 換句話說,建構類型的輔助功能定義域是其組成部分之輔助功能定義域的交集。
注意。 建構型別的輔助功能定義域是其構成部分的交集,具有定義新輔助功能層級的有趣副作用。 建構型別,其中包含的 Protected 元素,以及Friend只能在可存取和Protected 成員的內容中存取Friend的專案。 不過,無法以語言表示此輔助功能層級,因為輔助功能Protected Friend表示可以在可存取或Protected成員的內容中存取Friend實體。
建構型別的基底、實作介面和成員是由替代泛型型別中每個類型參數提供的型別自變數所決定。
開啟類型與封閉類型
一或多個型別自變數的建構型別是包含型別或方法的類型參數,稱為 開放式型別。 這是因為類型的某些類型參數仍然未知,因此類型的實際形狀尚未完全瞭解。 相反地,類型自變數為所有非型別參數的泛型型別稱為 封閉型別。 封閉類型的形狀一律為完全已知。 例如:
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
建構的類型是開放式類型 Base(Of Integer, V) ,因為雖然已提供類型參數 T ,但類型參數 U 已提供另一個類型參數。 因此,目前還不清楚型別的完整形狀。 不過,建構的類型是封閉類型 Derived(Of Double),因為已提供繼承階層中的所有類型參數。
開啟類型的定義如下:
類型參數是開啟的類型。
如果數位類型是開啟類型,則數位類型為開啟類型。
如果其中一或多個型別自變數是開啟類型,則建構類型是開放式類型。
封閉類型是不是開啟類型的類型。
因為程式進入點不能在泛型類型中,所以運行時間使用的所有類型都會是關閉的類型。
特殊類型
.NET Framework 包含一些類別,這些類別是由 .NET Framework 和 Visual Basic 語言特別處理的:
型 System.Void別 ,表示 .NET Framework 中的 void 型別,只能在表達式中 GetType 直接參考。
型 System.RuntimeArgumentHandle別 和 System.ArgIteratorSystem.TypedReference 全部都可以包含堆疊中的指標,因此不能出現在 .NET Framework 堆積上。 因此,它們不能當做數位專案類型、傳回型別、欄位類型、泛型型別自變數、可為 Null 的類型、參數型別、ByRef要轉換成 Object 或System.ValueType的值類型、呼叫實例成員ObjectSystem.ValueType的目標,或提升為關閉。