Visual Basic プログラムは、1 つ以上のソース ファイルで構成されます。 プログラムがコンパイルされると、すべてのソース ファイルが一緒に処理されます。したがって、ソース ファイルは、前方宣言の要件なしで、場合によっては循環形式で相互に依存できます。 プログラム テキスト内の宣言のテキスト順序は、通常、意味がありません。
ソース ファイルは、オプションの一連のオプション ステートメント、import ステートメント、および属性で構成され、その後に名前空間本体が続きます。 各属性には、 Assembly 修飾子または Module 修飾子が必要であり、コンパイルによって生成された .NET アセンブリまたはモジュールに適用されます。 ソース ファイルの本文は、グローバル名前空間の暗黙的な名前空間宣言として機能します。つまり、ソース ファイルの最上位レベルのすべての宣言がグローバル名前空間に配置されます。 例えば次が挙げられます。
FileA.vb:
Class A
End Class
FileB.vb:
Class B
End Class
この 2 つのソース ファイルはグローバル名前空間に寄与し、この場合は完全修飾名を持つ 2 つのクラス A 宣言し、 B。 2 つのソース ファイルは同じ宣言空間に影響するため、それぞれが同じ名前のメンバーの宣言を含む場合はエラーになります。
"注: コンパイル環境では、ソース ファイルが暗黙的に配置される名前空間宣言をオーバーライドできます。
記載されている場合を除き、Visual Basic プログラム内のステートメントは、行ターミネータまたはコロンによって終了できます。
Start
: OptionStatement* ImportsStatement* AttributesStatement* NamespaceMemberDeclaration*
;
StatementTerminator
: LineTerminator
| ':'
;
AttributesStatement
: Attributes StatementTerminator
;
プログラムの起動と終了
プログラムの起動は、実行環境が指定されたメソッド (プログラムの エントリ ポイントと呼ばれる) を実行するときに発生します。 このエントリ ポイント メソッドは、常に Main名前を付ける必要があり、共有する必要があり、ジェネリック型に含めることはできません。非同期修飾子を持つことができず、次のいずれかのシグネチャを持つ必要があります。
Sub Main()
Sub Main(args() As String)
Function Main() As Integer
Function Main(args() As String) As Integer
エントリ ポイント メソッドのアクセシビリティは関係ありません。 プログラムに複数の適切なエントリ ポイントが含まれている場合は、コンパイル環境でエントリ ポイントとして 1 つを指定する必要があります。 それ以外の場合は、コンパイル時エラーが発生します。 コンパイル環境では、エントリ ポイント メソッドが存在しない場合にも作成できます。
プログラムの開始時に、エントリ ポイントにパラメーターがある場合、実行環境によって提供される引数には、文字列として表されるプログラムへのコマンド ライン引数が含まれます。 エントリ ポイントの戻り値の型が Integer の場合、関数から返された値はプログラムの結果として実行環境に返されます。
それ以外の点では、エントリ ポイント メソッドは他のメソッドと同じ方法で動作します。 実行環境によって行われたエントリ ポイント メソッドの呼び出しから実行が終了すると、プログラムは終了します。
コンパイル オプション
ソース ファイルでは、 option ステートメントを使用してソース コードでコンパイル オプションを指定できます。
OptionStatement
: OptionExplicitStatement
| OptionStrictStatement
| OptionCompareStatement
| OptionInferStatement
;
Option ステートメントは、そのステートメントが表示されるソース ファイルにのみ適用され、ソース ファイルに表示できるOptionステートメントの種類は 1 つだけです。 例えば次が挙げられます。
Option Strict On
Option Compare Text
Option Strict Off ' Not allowed, Option Strict is already specified.
Option Compare Text ' Not allowed, Option Compare is already specified.
厳密な型セマンティクス、明示的宣言セマンティクス、比較セマンティクス、ローカル変数型推論セマンティクスの 4 つのコンパイル オプションがあります。 ソース ファイルに特定の Option ステートメントが含まれていない場合、コンパイル環境によって、使用される特定のセマンティクスセットが決定されます。 5 番目のコンパイル オプションである整数オーバーフロー チェックもあります。これはコンパイル環境でのみ指定できます。
Option Explicit ステートメント
Option Explicit ステートメントは、ローカル変数を暗黙的に宣言できるかどうかを決定します。 キーワード On または Off はステートメントの後に続く場合があります。どちらも指定されていない場合、既定値は On。 ファイルにステートメントが指定されていない場合、コンパイル環境によって使用されるステートメントが決まります。
OptionExplicitStatement
: 'Option' 'Explicit' OnOff? StatementTerminator
;
OnOff
: 'On' | 'Off'
;
"注:
Explicit と Off は予約語ではありません。
Option Explicit Off
Module Test
Sub Main()
x = 5 ' Valid because Option Explicit is off.
End Sub
End Module
この例では、ローカル変数 x を代入することによって暗黙的に宣言します。
x の型は Object です。
Option Strict ステートメント
Option Strict ステートメントは、Objectに対する変換と操作を厳密な型セマンティクスまたは制限のない型セマンティクスによって制御するかどうか、およびAs句が指定されていない場合に型をObjectとして暗黙的に型指定するかどうかを決定します。 ステートメントの後にキーワード On または Offを指定できます。どちらも指定されていない場合、既定値は On。 ファイルにステートメントが指定されていない場合、コンパイル環境によって使用されるステートメントが決まります。
OptionStrictStatement
: 'Option' 'Strict' OnOff? StatementTerminator
;
"注:
Strict と Off は予約語ではありません。
Option Strict On
Module Test
Sub Main()
Dim x ' Error, no type specified.
Dim o As Object
Dim b As Byte = o ' Error, narrowing conversion.
o.F() ' Error, late binding disallowed.
o = o + 1 ' Error, addition is not defined on Object.
End Sub
End Module
厳密なセマンティクスでは、以下は許可されません。
明示的なキャスト演算子を使用せずに変換を縮小する。
遅延バインディング。
TypeOf...Is、Is、およびIsNot以外の型Objectに対する操作。推論された型を持たない宣言で
As句を省略する。
Option Compare ステートメント
Option Compare ステートメントは、文字列比較のセマンティクスを決定します。 文字列比較は、バイナリ比較 (各文字のバイナリ Unicode 値を比較する) またはテキスト比較 (現在のカルチャを使用して各文字の字句の意味を比較する) を使用して実行されます。 ファイルにステートメントが指定されていない場合、コンパイル環境は使用する比較の種類を制御します。
OptionCompareStatement
: 'Option' 'Compare' CompareOption StatementTerminator
;
CompareOption
: 'Binary' | 'Text'
;
Note.Compare、 Binary、 Text は予約語ではありません。
Option Compare Text
Module Test
Sub Main()
Console.WriteLine("a" = "A") ' Prints True.
End Sub
End Module
この場合、文字列比較は、大文字と小文字の違いを無視するテキスト比較を使用して行われます。
Option Compare Binary指定されている場合は、False出力されます。
整数オーバーフロー チェック
整数演算は、実行時にオーバーフロー状態をチェックするか、チェックできません。 オーバーフロー条件がチェックされ、整数演算がオーバーフローすると、 System.OverflowException 例外がスローされます。 オーバーフロー条件がチェックされていない場合、整数演算オーバーフローは例外をスローしません。 コンパイル環境は、このオプションがオンかオフかを決定します。
Option Infer ステートメント
Option Infer ステートメントは、As句を持たないローカル変数宣言が推論された型を持っているか、Objectを使用するかを決定します。 ステートメントの後にキーワード On または Offを指定できます。どちらも指定されていない場合、既定値は On。 ファイルにステートメントが指定されていない場合、コンパイル環境によって使用されるステートメントが決まります。
OptionInferStatement
: 'Option' 'Infer' OnOff? StatementTerminator
;
"注:
Infer と Off は予約語ではありません。
Option Infer On
Module Test
Sub Main()
' The type of x is Integer
Dim x = 10
' The type of y is String
Dim y = "abc"
End Sub
End Module
Imports ステートメント
Imports ステートメントはエンティティの名前をソース ファイルにインポートし、修飾なしで名前を参照したり、XML 式で使用する名前空間をインポートしたりできます。
ImportsStatement
: 'Imports' ImportsClauses StatementTerminator
;
ImportsClauses
: ImportsClause ( Comma ImportsClause )*
;
ImportsClause
: AliasImportsClause
| MembersImportsClause
| XMLNamespaceImportsClause
;
Imports ステートメントを含むソース ファイル内のメンバー宣言内では、次の例に示すように、指定された名前空間に含まれる型を直接参照できます。
Imports N1.N2
Namespace N1.N2
Class A
End Class
End Namespace
Namespace N3
Class B
Inherits A
End Class
End Namespace
ここでは、ソース ファイル内で名前空間 N1.N2 の型メンバーを直接使用できるため、クラス N3.B はクラス N1.N2.Aから派生します。
Imports ステートメントは、任意の Option ステートメントの後に、型宣言の前に記述する必要があります。 コンパイル環境では、暗黙的な Imports ステートメントを定義することもできます。
Imports ステートメントはソース ファイルで名前を使用できるようにしますが、グローバル名前空間の宣言空間では何も宣言しません。
Imports ステートメントによってインポートされる名前のスコープは、ソース ファイルに含まれる名前空間メンバー宣言に拡張されます。
Imports ステートメントのスコープには、特に他のImports ステートメントは含まれません。また、他のソース ファイルも含まれません。
Imports ステートメントが相互に参照されない場合があります。
この例では、最初のインポート エイリアスの影響を受けないため、最後の Imports ステートメントがエラーになります。
Imports R1 = N1 ' OK.
Imports R2 = N1.N2 ' OK.
Imports R3 = R1.N2 ' Error: Can't refer to R1.
Namespace N1.N2
End Namespace
"注:
Importsステートメントに表示される名前空間または型名は、常に完全修飾名として扱われます。 つまり、名前空間または型名の左端の識別子は常にグローバル名前空間で解決され、残りの解決は通常の名前解決規則に従って続行されます。 これは、このようなルールを適用する言語の唯一の場所です。規則により、名前を修飾から完全に非表示にすることはできません。 ルールがないと、グローバル名前空間内の名前が特定のソース ファイルに隠されていた場合、その名前空間の名前を修飾された方法で指定することはできません。
この例では、 Imports ステートメントは常に、ソース ファイル内のクラスではなく、グローバル System 名前空間を参照します。
Imports System ' Imports the namespace, not the class.
Class System
End Class
エイリアスのインポート
インポート エイリアスは、名前空間または型のエイリアスを定義します。
AliasImportsClause
: Identifier Equals TypeName
;
Imports A = N1.N2.A
Namespace N1.N2
Class A
End Class
End Namespace
Namespace N3
Class B
Inherits A
End Class
End Namespace
ここでは、ソース ファイル内で、 A は N1.N2.Aのエイリアスであるため、クラス N3.B はクラス N1.N2.Aから派生します。
R のエイリアス N1.N2 を作成し、R.A を参照することで、同じ効果を得ることができます。
Imports R = N1.N2
Namespace N3
Class B
Inherits R.A
End Class
End Namespace
インポート エイリアスの識別子は、グローバル名前空間の宣言空間で名前を宣言しない場合でも、(インポート エイリアスが定義されているソース ファイル内のグローバル名前空間宣言だけでなく) グローバル名前空間の宣言空間内で一意である必要があります。
"注: モジュール内の宣言では、含まれる宣言空間に名前は導入されません。 したがって、モジュール内の宣言にインポート エイリアスと同じ名前を付けるのは有効です。ただし、宣言の名前は、含まれている宣言空間でアクセスできます。
' Error: Alias A conflicts with typename A
Imports A = N3.A
Class A
End Class
Namespace N3
Class A
End Class
End Namespace
ここでは、グローバル名前空間には既にメンバー Aが含まれているため、インポート エイリアスがその識別子を使用するのはエラーです。 同様に、同じソース ファイル内の 2 つ以上のインポート エイリアスが同じ名前でエイリアスを宣言するとエラーになります。
インポート エイリアスは、任意の名前空間または型のエイリアスを作成できます。 エイリアスを使用して名前空間または型にアクセスすると、宣言された名前を使用して名前空間または型にアクセスするのとまったく同じ結果が得られます。
Imports R1 = N1
Imports R2 = N1.N2
Namespace N1.N2
Class A
End Class
End Namespace
Namespace N3
Class B
Private a As N1.N2.A
Private b As R1.N2.A
Private c As R2.A
End Class
End Namespace
ここでは、 N1.N2.A、 R1.N2.A、および R2.A の名前は同等であり、すべて完全修飾名が N1.N2.Aクラスを参照します。
インポートでは、エイリアスを作成する名前空間または型の正確な名前を指定します。 これは、その名前空間または型の正確な完全修飾名である必要があります。修飾名解決には通常の規則を使用しません (たとえば、派生クラスを介して基底クラスのメンバーへのアクセスを許可します)。
インポート エイリアスが、これらの規則で解決できない型または名前空間を指している場合、import ステートメントは無視されます (コンパイラによって警告が表示されます)。
また、開いているジェネリック型への参照を指定することはできません。すべてのジェネリック型には有効な型引数を指定する必要があり、すべての型引数は上記の規則で解決できる必要があります。 ジェネリック型のバインドが正しくない場合は、エラーになります。
Imports A = G ' error: since G is an open generic type
Imports B = G(Of Integer) ' okay
Imports C = Derived.Nested ' warning: Derived.Nested isn't itself a type
Imports D = G(Of Derived.Nested) ' error: Derived.Nested isn't found
Class G(Of T) : End Class
Class Base
Class Nested : End Class
End Class
Class Derived : Inherits Base
End Class
Module Module1
Sub Main()
Dim x As C ' error: "C" wasn't succesfully defined
Dim y As Derived.Nested ' okay
End Sub
End Module
ソース ファイル内の宣言は、インポートエイリアス名をシャドウする可能性があります。
Imports R = N1.N2
Namespace N1.N2
Class A
End Class
End Namespace
Namespace N3
Class R
End Class
Class B
Inherits R.A ' Error, R has no member A
End Class
End Namespace
前の例では、Bの宣言でR.Aを参照すると、RはN1.N2ではなくN3.Rを参照するため、エラーが発生します。
インポート エイリアスは、特定のソース ファイル内でエイリアスを使用できるようにしますが、基になる宣言空間に新しいメンバーを提供しません。 つまり、インポート エイリアスは推移的ではなく、発生するソース ファイルにのみ影響します。
File1.vb:
Imports R = N1.N2
Namespace N1.N2
Class A
End Class
End Namespace
File2.vb:
Class B
Inherits R.A ' Error, R unknown.
End Class
上記の例では、 R を導入するインポート エイリアスのスコープは、それが含まれているソース ファイル内の宣言にのみ拡張されるため、 R は 2 番目のソース ファイルでは不明です。
名前空間のインポート
名前空間インポートは、名前空間または型のすべてのメンバーをインポートし、名前空間または型の各メンバーの識別子を修飾なしで使用できるようにします。 型の場合、名前空間のインポートでは、クラス名の修飾を必要とせずに、型の共有メンバーへのアクセスのみが許可されます。 特に、列挙型のメンバーを修飾なしで使用できます。
MembersImportsClause
: TypeName
;
例えば次が挙げられます。
Imports Colors
Enum Colors
Red
Green
Blue
End Enum
Module M1
Sub Main()
Dim c As Colors = Red
End Sub
End Module
インポートエイリアスとは異なり、名前空間のインポートにはインポートする名前に制限はなく、識別子がグローバル名前空間内で既に宣言されている名前空間と型をインポートできます。 通常のインポートによってインポートされた名前は、ソース ファイル内のインポート エイリアスと宣言によってシャドウされます。
次の例では、Aは、N3名前空間のメンバー宣言内でN1.N2.Aするのではなく、N3.Aを参照します。
Imports N1.N2
Namespace N1.N2
Class A
End Class
End Namespace
Namespace N3
Class A
End Class
Class B
Inherits A
End Class
End Namespace
インポートされた複数の名前空間に同じ名前のメンバーが含まれている場合 (また、その名前がインポートエイリアスまたは宣言によってシャドウされない場合)、その名前への参照があいまいになり、コンパイル時エラーが発生します。
Imports N1
Imports N2
Namespace N1
Class A
End Class
End Namespace
Namespace N2
Class A
End Class
End Namespace
Namespace N3
Class B
Inherits A ' Error, A is ambiguous.
End Class
End Namespace
上記の例では、 N1 と N2 の両方にメンバー Aが含まれています。
N3は両方をインポートするため、N3でAを参照するとコンパイル時エラーが発生します。 この状況では、次の例のように、 Aへの参照の修飾を使用するか、特定の Aを選択するインポート エイリアスを導入することで、競合を解決できます。
Imports N1
Imports N2
Imports A = N1.A
Namespace N3
Class B
Inherits A ' A means N1.A.
End Class
End Namespace
インポートできるのは、名前空間、クラス、構造体、列挙型、および標準モジュールのみです。
XML 名前空間のインポート
XML 名前空間のインポートでは、コンパイル ユニット内に含まれる修飾されていない XML 式の名前空間または既定の名前空間を定義します。
XMLNamespaceImportsClause
: '<' XMLNamespaceAttributeName XMLWhitespace? Equals XMLWhitespace?
XMLNamespaceValue '>'
;
XMLNamespaceValue
: DoubleQuoteCharacter XMLAttributeDoubleQuoteValueCharacter* DoubleQuoteCharacter
| SingleQuoteCharacter XMLAttributeSingleQuoteValueCharacter* SingleQuoteCharacter
;
例えば次が挙げられます。
Imports <xmlns:db="http://example.org/database">
Module Test
Sub Main()
' db namespace is "http://example.org/database"
Dim x = <db:customer><db:Name>Bob</></>
Console.WriteLine(x.<db:Name>)
End Sub
End Module
既定の名前空間を含む XML 名前空間は、特定のインポート セットに対して 1 回だけ定義できます。 例えば次が挙げられます。
Imports <xmlns:db="http://example.org/database-one">
' Error: namespace db is already defined
Imports <xmlns:db="http://example.org/database-two">
名前空間
Visual Basic プログラムは、名前空間を使用して編成されます。 名前空間は、プログラムを内部的に編成するだけでなく、プログラム要素が他のプログラムに公開される方法を整理します。
他のエンティティとは異なり、名前空間はオープン エンドであり、同じプログラム内および多くのプログラム間で複数回宣言でき、各宣言はメンバーを同じ名前空間に提供します。 次の例では、2 つの名前空間宣言が同じ宣言空間に含まれており、完全修飾名が N1.N2.A と N1.N2.Bで 2 つのクラスが宣言されています。
Namespace N1.N2
Class A
End Class
End Namespace
Namespace N1.N2
Class B
End Class
End Namespace
2 つの宣言は同じ宣言空間に影響するため、それぞれが同じ名前のメンバーの宣言を含む場合はエラーになります。
名前がなく、入れ子になった名前空間と型に常に修飾なしでアクセスできるグローバル名前空間があります。 グローバル名前空間で宣言されている名前空間メンバーのスコープは、プログラム テキスト全体です。 それ以外の場合、完全修飾名が N されている名前空間で宣言された型または名前空間のスコープは、対応する名前空間の完全修飾名が N で始まるか、 N 自体である各名前空間のプログラム テキストです。 (コンパイラは、既定で特定の名前空間に宣言を配置することを選択できることに注意してください。これは、グローバルな名前のない名前空間がまだ存在するという事実を変えるものではありません。
この例では、Bの名前空間N1.N2.N3が名前空間N1.N2内で概念的に入れ子になっているため、クラス BはクラスのAを確認できます。
Namespace N1.N2
Class A
End Class
End Namespace
Namespace N1.N2.N3
Class B
Inherits A
End Class
End Namespace
名前空間の宣言
名前空間宣言には 3 つの形式があります。
NamespaceDeclaration
: 'Namespace' NamespaceName StatementTerminator
NamespaceMemberDeclaration*
'End' 'Namespace' StatementTerminator
;
NamespaceName
: RelativeNamespaceName
| 'Global'
| 'Global' '.' RelativeNamespaceName
;
RelativeNamespaceName
: Identifier ( Period IdentifierOrKeyword )*
;
最初の形式はキーワード Namespace で始まり、その後に相対名前空間名が続きます。 相対名前空間名が修飾されている場合、名前空間宣言は、修飾名の各名前に対応する名前空間宣言内で構文的に入れ子になっているかのように扱われます。 たとえば、次の 2 つの名前空間は意味的に同等です。
Namespace N1.N2
Class A
End Class
Class B
End Class
End Namespace
Namespace N1
Namespace N2
Class A
End Class
Class B
End Class
End Namespace
End Namespace
2 番目のフォームは、キーワード Namespace Globalで始まります。 コンパイル環境によって提供される既定値に関係なく、すべてのメンバー宣言がグローバルな名前のない名前空間に構文的に配置されたかのように扱われます。 この形式の名前空間宣言は、他の名前空間宣言内で字句的に入れ子にすることはできません。
3 番目の形式は、キーワード Namespace Global の後に修飾された識別子 Nで始まります。 コンパイル環境によって提供される既定値に関係なく、グローバルな名前のない名前空間に構文的に配置された最初の形式 "Namespace N" の名前空間宣言であるかのように扱われます。 この形式の名前空間宣言は、他の名前空間宣言内で字句的に入れ子にすることはできません。
Namespace Global ' Puts N1.A in the global namespace
Namespace N1
Class A
End Class
End Namespace
End Namespace
Namespace Global.N1 ' Equivalent to the above
Class A
End Class
End Namespace
Namespace N1 ' May or may not be equivalent to the above,
Class A ' depending on defaults provided by the
End Class ' compilation environment
End Namespace
名前空間のメンバーを処理する場合、特定のメンバーを宣言する場所は重要ではありません。 2 つのプログラムが同じ名前空間に同じ名前のエンティティを定義している場合、名前空間内の名前を解決しようとするとあいまいエラーが発生します。
名前空間は定義上 Publicであるため、名前空間宣言にアクセス修飾子を含めることはできません。
名前空間メンバー
名前空間のメンバーには、名前空間宣言と型宣言のみを指定できます。 型宣言には、 Public または Friend アクセス権が含まれる場合があります。 型の既定のアクセスは Friend アクセスです。
NamespaceMemberDeclaration
: NamespaceDeclaration
| TypeDeclaration
;
TypeDeclaration
: ModuleDeclaration
| NonModuleDeclaration
;
NonModuleDeclaration
: EnumDeclaration
| StructureDeclaration
| InterfaceDeclaration
| ClassDeclaration
| DelegateDeclaration
;
Visual Basic language spec