Visual Basic の型の 2 つの基本的なカテゴリは、 値型 と 参照型です。 プリミティブ型 (文字列を除く)、列挙型、および構造体は値型です。 クラス、文字列、標準モジュール、インターフェイス、配列、およびデリゲートは参照型です。
すべての型には 既定値があり、これは初期化時にその型の変数に割り当てられる値です。
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; は、 ref1 参照と ref2 参照の両方のオブジェクトに影響します。
.NET Framework 型システムについて注意すべき点の 1 つは、構造体、列挙体、およびプリミティブ型 ( Stringを除く) が値型であっても、それらはすべて参照型から継承されるということです。 構造体とプリミティブ型は、Objectから継承する参照型System.ValueTypeを継承します。 列挙型は、System.ValueTypeから継承する参照型System.Enumを継承します。
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)型と同義であり、2 つの名前を同じ意味で使用できます。
?修飾子は、既に null 許容の型には配置できません。したがって、型Integer??またはSystem.Nullable(Of Integer)?を宣言することはできません。
null 許容値型T?には、System.Nullable(Of T)のメンバーと、基になる型TからT?に持ち上げられた演算子または変換が含まれます。 リフティングでは、基になる型からのコピー演算子と変換が行われます。ほとんどの場合、null 非許容値型に null 許容値型を置き換えます。 これにより、 T に適用される同じ変換と操作の多くを T? にも適用できます。
インターフェイスの実装
構造体とクラスの宣言では、1 つ以上の 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
型自体でインターフェイスを実装することを宣言しても、型の宣言空間では何も宣言されません。 したがって、同じ名前のメソッドを使用して 2 つのインターフェイスを実装することが有効です。
型は独自に型パラメーターを実装できませんが、スコープ内の型パラメーターが含まれる場合があります。
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 バイト符号なし整数)、SByte(1 バイト符号付き整数)、UShort(2 バイト符号なし整数)、Short(2 バイト符号付き整数)、UInteger(4 バイト符号なし整数)、Integer(4 バイト符号付き整数)、ULong(8 バイト符号なし整数)、およびLong(8 バイト符号付き整数) です。 これらの型はそれぞれ、System.Byte、System.SByte、System.UInt16、System.Int16、System.UInt32、System.Int32、System.UInt64、およびSystem.Int64にマップされます。 整数型の既定値は、リテラル0と同じです。浮動小数点値の型
Single(4 バイト浮動小数点) とDouble(8 バイト浮動小数点) です。 これらの型は、それぞれSystem.SingleとSystem.Doubleにマップされます。 浮動小数点型の既定値は、リテラル0と同じです。System.DecimalにマップされるDecimal型 (16 バイトの 10 進値)。 decimal の既定値は、リテラル0Dと同じです。信頼できる値を表す
Boolean値型は、通常、リレーショナル操作または論理演算の結果です。 リテラルはSystem.Boolean型です。Boolean型の既定値は、リテラルFalseと同じです。Date値型。日付または時刻を表し、System.DateTimeにマップされます。Date型の既定値は、リテラル# 01/01/0001 12:00:00AM #と同じです。Char値型。1 つの 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、 SByte、 UShort、 Short、 UInteger、 Integer、 ULong、 Long、または System 名前空間内の対応する型のいずれかである必要があります。 基になる型が明示的に指定されていない場合、既定値は 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
この例では、同じ値を持つ 2 つの列挙メンバー ( 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列挙値には、テキストで先行する列挙値より 1 大きい値が自動的に割り当てられます。
定数式は、関連する独自の列挙値の値を直接または間接的に使用することはできません (つまり、定数式の循環性は許可されません)。 次の例は、 A と B の宣言が循環しているため無効です。
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
クラス固有の修飾子には、 MustInherit と NotInheritableの 2 つがあります。 両方を指定することは無効です。
クラスの基本仕様
クラス宣言には、クラスの直接基本型を定義する基本型の仕様を含めることができます。
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.Enum、 System.Array、 System.MulticastDelegate 、または System.Delegateから派生することは無効です。 ジェネリック クラスは、 System.Attribute から派生することも、そこから派生したクラスから派生することもできません。
すべてのクラスに直接基底クラスが 1 つだけ含まれており、派生での循環性は禁止されています。
NotInheritable クラスから派生することはできません。また、基底クラスのアクセシビリティ ドメインは、クラス自体のアクセシビリティ ドメインと同じかスーパーセットである必要があります。
クラス メンバー
クラスのメンバーは、そのクラス メンバー宣言によって導入されたメンバーと、その直接基底クラスから継承されたメンバーで構成されます。
ClassMemberDeclaration
: NonModuleDeclaration
| EventMemberDeclaration
| VariableMemberDeclaration
| ConstantMemberDeclaration
| MethodMemberDeclaration
| PropertyMemberDeclaration
| ConstructorMemberDeclaration
| OperatorDeclaration
;
クラス メンバー宣言には、 Public、 Protected、 Friend、 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'
;
クラスの場合、2 つの変数が同じオブジェクトを参照できるため、1 つの変数に対する操作が他の変数によって参照されるオブジェクトに影響を与える可能性があります。 構造体では、次の例に示すように、変数にはそれぞれ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されます。
Structure メンバー
構造体のメンバーは、構造体メンバー宣言によって導入されたメンバーと、 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
上記の宣言を指定すると、次のステートメントは両方とも、xを持つPointを作成し、y 0 に初期化します。
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
通常、構造体メンバー宣言には Public、 Friend、または Private アクセス権のみが含まれますが、 Objectから継承されたメンバーをオーバーライドする場合は、 Protected および Protected Friend アクセスも使用できます。 構造体メンバー宣言にアクセス修飾子が含まれていない場合、宣言の既定値はアクセス Public 。 構造体によって宣言されたメンバーのスコープは、宣言が行われる構造体本体に加えて、その構造体の制約 (ジェネリックで制約がある場合) です。
標準モジュール
標準モジュールは、メンバーが暗黙的にSharedされ、標準モジュール宣言自体ではなく、標準モジュールの包含名前空間の宣言空間にスコープが設定される型です。 標準モジュールをインスタンス化することはできません。 標準モジュール型の変数を宣言するとエラーになります。
ModuleDeclaration
: Attributes? TypeModifier* 'Module' Identifier StatementTerminator
ModuleMemberDeclaration*
'End' 'Module' StatementTerminator
;
標準モジュールのメンバーには 2 つの完全修飾名があり、1 つは標準モジュール名を持たず、1 つは標準モジュール名を持っています。 名前空間内の複数の標準モジュールで、特定の名前を持つメンバーを定義できます。どちらのモジュールの外部の名前に対する修飾されていない参照もあいまいです。 例えば次が挙げられます。
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 コンストラクターのみを持ちます。
Standard モジュール メンバー
標準モジュールのメンバーは、そのメンバー宣言によって導入されたメンバーと、 Objectから継承されたメンバーです。 標準モジュールには、インスタンス コンストラクターを除く任意の型のメンバーが含まれる場合があります。 すべての標準モジュール型メンバーは暗黙的に Shared。
ModuleMemberDeclaration
: NonModuleDeclaration
| VariableMemberDeclaration
| ConstantMemberDeclaration
| EventMemberDeclaration
| MethodMemberDeclaration
| PropertyMemberDeclaration
| ConstructorMemberDeclaration
;
通常、標準のモジュール メンバー宣言には Public、 Friend、または Private アクセス権のみが含まれますが、 Objectから継承されたメンバーをオーバーライドする場合は、 Protected および Protected Friend アクセス修飾子を指定できます。 標準モジュール メンバー宣言にアクセス修飾子が含まれていない場合、宣言は、既定でアクセス 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 を継承します。
インターフェイスを実装するクラスまたは構造体は、インターフェイスのすべての基本インターフェイスも暗黙的に実装します。
インターフェイスが基底インターフェイスの推移的なクロージャに複数回出現する場合、そのメンバーは派生インターフェイスに 1 回だけ提供されます。 派生インターフェイスを実装する型は、乗算で定義された基本インターフェイスのメソッドを 1 回だけ実装する必要があります。 次の例では、クラスがIComboBoxとIControlを実装する場合でも、Paintは 1 回だけ実装する必要があります。
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
基本インターフェイスのアクセシビリティ ドメインは、インターフェイス自体のアクセシビリティ ドメインと同じか、スーパーセットである必要があります。
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を持つ 1 次元配列型は、インターフェイスのSystem.Collections.Generic.IList(Of T)とIReadOnlyList(Of T)も実装します。Tが参照型の場合、配列型は、Tからの拡大参照変換を持つ任意のUのIList(Of U)とIReadOnlyList(Of U)も実装します。
配列には、各配列要素に関連付けられているインデックスの数を決定する ランク があります。 配列のランクによって、配列の 次元 数が決まります。 たとえば、ランクが 1 の配列は 1 次元配列と呼ばれ、ランクが 1 より大きい配列は多次元配列と呼ばれます。
次の例では、整数値の 1 次元配列を作成し、配列要素を初期化して、それぞれを出力します。
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のディメンションの場合、インデックスの範囲は 0 から N-1。 ディメンションが長さ 0 の場合、そのディメンションの有効なインデックスはありません。 配列内の要素の合計数は、配列内の各次元の長さの積です。 配列のいずれかの次元の長さが 0 の場合、配列は空と見なされます。 配列の要素型には、任意の型を指定できます。
配列型は、既存の型名に修飾子を追加することによって指定されます。 修飾子は、左かっこ、0 個以上のコンマのセット、および右かっこで構成されます。 変更された型は配列の要素型であり、次元の数はコンマの数に 1 を加えた値です。 複数の修飾子が指定されている場合、配列の要素型は配列になります。 修飾子は左から右に読み取られ、左端の修飾子が最も外側の配列になります。 この例では
Module Test
Dim arr As Integer(,)(,,)()
End Module
arrの要素型は、Integerの 1 次元配列の 3 次元配列の 2 次元配列です。
変数は、配列型修飾子または配列サイズ初期化修飾子を変数名に配置することで、配列型として宣言することもできます。 その場合、配列要素の型は宣言で指定された型であり、配列の次元は変数名修飾子によって決定されます。 わかりやすくするために、変数名と型名の両方に配列型修飾子を同じ宣言に含めるのは有効ではありません。
次の例は、 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
;
他の言語のデリゲートに最も近いのは関数ポインターですが、関数ポインターは Shared 関数のみを参照できますが、デリゲートは Shared メソッドとインスタンス メソッドの両方を参照できます。 後者の場合、デリゲートはメソッドのエントリ ポイントへの参照だけでなく、メソッドを呼び出すオブジェクト インスタンスへの参照も格納します。
デリゲート宣言には、 Handles 句、 Implements 句、メソッド本体、または End コンストラクトを含めないようにすることができます。 デリゲート宣言のパラメーター リストには、 Optional または ParamArray パラメーターが含まれていない場合があります。 戻り値の型とパラメーター型のアクセシビリティ ドメインは、デリゲート自体のアクセシビリティ ドメインと同じか、スーパーセットである必要があります。
デリゲートのメンバーは、クラス System.Delegateから継承されたメンバーです。 デリゲートは、次のメソッドも定義します。
2 つのパラメーターを受け取るコンストラクター。
Object型の 1 つとSystem.IntPtr型のいずれかです。デリゲートと同じシグネチャを持つ
Invokeメソッド。シグネチャがデリゲート シグネチャである
BeginInvokeメソッド。3 つの違いがあります。 最初に、戻り値の型がSystem.IAsyncResultに変更されます。 次に、パラメーター リストの末尾に 2 つのパラメーターが追加されます。1 番目の型System.AsyncCallbackと 2 番目の型Object。 最後に、すべてのByRefパラメーターがByValに変更されます。戻り値の型がデリゲートと同じ
EndInvokeメソッド。 メソッドのパラメーターは、デリゲート シグネチャで発生するのと同じ順序で、ByRefパラメーターであるデリゲート パラメーターだけです。 これらのパラメーターに加えて、パラメーター リストの末尾にSystem.IAsyncResult型の追加パラメーターがあります。
デリゲートの定義と使用には、宣言、インスタンス化、呼び出しの 3 つの手順があります。
デリゲートは、デリゲート宣言構文を使用して宣言されます。 次の例では、引数を受け取っていない 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
メソッドのデリゲートをインスタンス化してから、デリゲートを介してすぐに呼び出すことは、メソッドを直接呼び出す方が簡単であるため、あまり意味がありません。 代理人は、匿名性を使用する場合の有用性を示します。 次の例は、SimpleDelegate インスタンスを繰り返し呼び出すMultiCall メソッドを示しています。
Sub MultiCall(d As SimpleDelegate, count As Integer)
Dim i As Integer
For i = 0 To count - 1
d()
Next i
End Sub
SimpleDelegateのターゲット メソッドが何であるか、このメソッドが持つアクセシビリティ、またはメソッドがSharedされているかどうかをMultiCallメソッドにとって重要ではありません。 重要なのは、ターゲット メソッドのシグネチャが SimpleDelegateと互換性があるということです。
部分型
クラスと構造体の宣言は、 部分 宣言にすることができます。 部分宣言は、宣言内で宣言された型を完全に記述する場合と完全に記述できない場合があります。 代わりに、型の宣言は、プログラム内の複数の部分宣言に分散される可能性があります。部分型は、プログラムの境界を越えて宣言することはできません。 部分型宣言は、宣言の Partial 修飾子を指定します。 その後、同じ完全修飾名を持つ型に対するプログラム内の他の宣言は、コンパイル時に部分宣言とマージされ、1 つの型宣言が形成されます。 たとえば、次のコードは、メンバーがTest.C1およびTest.C2を持つ 1 つのクラス 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
部分型宣言を組み合わせる場合、少なくとも 1 つの宣言に Partial 修飾子が必要です。それ以外の場合はコンパイル時エラーが発生します。
"注: 多くの部分宣言の中で 1 つの宣言にのみ Partial を指定することはできますが、すべての部分宣言で指定することをお勧めします。 1 つの部分宣言が表示されていても、1 つ以上の部分宣言が非表示になっている場合 (ツールによって生成されたコードを拡張する場合など)、 Partial 修飾子は可視宣言から外したまま、非表示の宣言で指定することもできます。
部分宣言を使用して宣言できるのは、クラスと構造体だけです。 型のアリティは、部分宣言を一緒に照合する場合に考慮されます。同じ名前を持ち、型パラメーターの数が異なる 2 つのクラスは、同じ時刻の部分宣言とは見なされません。 部分宣言では、属性、クラス修飾子、 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
前の例では、Public、Objectから継承し、System.IDisposableとSystem.IComparableを実装する型Test1を宣言します。
Test2の部分的な宣言ではコンパイル時エラーが発生します。宣言の 1 つはTest2がPublic、もう 1 つは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。 構築された型の型引数の 1 つが Protected で、別の型引数が Friend場合、構築された型は、このアセンブリ内のクラスとそのサブクラス、またはアクセス Friend 与えられたアセンブリでのみアクセスできます。 つまり、構築された型のアクセシビリティ ドメインは、その構成要素のアクセシビリティ ドメインの共通部分です。
"注: 構築された型のアクセシビリティ ドメインがその構成部分の共通部分であるという事実は、新しいアクセシビリティ レベルを定義するという興味深い副作用があります。
Protectedされる要素とFriendされる要素を含む構築された型は、両方FriendandProtectedメンバーにアクセスできるコンテキストでのみアクセスできます。 ただし、アクセシビリティ Protected Friendは、いずれかのメンバーにアクセスできるコンテキストでエンティティにアクセスできることを意味するため、このアクセシビリティ レベルを言語で表現Friend方法はありませんProtected。
基本インターフェイス、実装されたインターフェイス、構築された型のメンバーは、ジェネリック型の型パラメーターが出現するたびに、指定された型引数を置き換えることによって決定されます。
開いている型と閉じた型
1 つ以上の型引数が含まれる型またはメソッドの型パラメーターである構築された型は、 オープン型と呼ばれます。 これは、型の型パラメーターの一部がまだ不明であるため、型の実際の形状がまだ完全にはわかっていないためです。 これに対し、型引数がすべて非型パラメーターであるジェネリック型は 、閉じた型と呼ばれます。 閉じた型の形状は常に完全に認識されます。 例えば次が挙げられます。
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)は、継承階層内のすべての型パラメーターが指定されているため、閉じた型です。
オープン型は次のように定義されます。
型パラメーターは、開いている型です。
配列型は、その要素型が開いている型の場合に開いている型です。
構築された型は、その型引数の 1 つ以上が開いている型の場合、開いている型です。
クローズド型はオープン型ではない型です。
プログラム エントリ ポイントをジェネリック型にすることはできませんので、実行時に使用されるすべての型は閉じた型になります。
特殊な型
.NET Framework には、.NET Framework と Visual Basic 言語によって特別に扱われる多くのクラスが含まれています。
.NET Framework の void 型を表す System.Void型は、 GetType 式でのみ直接参照できます。
型 System.RuntimeArgumentHandle、 System.ArgIterator 、 System.TypedReference はすべてスタックへのポインターを含めることができるため、.NET Framework ヒープには表示できません。 そのため、配列要素の型、戻り値の型、フィールド型、ジェネリック型の引数、null 許容型、 ByRef パラメーター型、 Object または System.ValueTypeに変換される値の型、 Object または System.ValueTypeのインスタンス メンバーへの呼び出しのターゲット、またはクロージャへのリフトとして使用することはできません。
Visual Basic language spec