Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Двумя основными категориями типов в 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
Назначение локальной переменной не влияет на локальную переменную val2val1 , поскольку как локальные переменные имеют тип значения (тип Integer), так как каждая локальная переменная типа значения имеет собственное хранилище. В отличие от этого, назначение ref2.Value = 123; влияет на объект, который ref2ref1 и ссылается.
Важно отметить, что система типов .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)?.
Тип значения, допускающего значение T? NULL, содержит элементы 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-байтовое целое число без знака),SByte(1-байтовое целое число со знаком), (2-байтовое целое число без знака),UShortShort(2-байтовое целое число со знаком),UInteger(4-байтовое целое число без знака),Integer(4-байтовое целое число),ULong(8-байтовое целое число без знака) иLong(8-байтовое целое число со знаком). Эти типы сопоставляют сSystem.Byte,System.UInt16System.SByte, ,System.UInt32System.Int16,System.Int32System.UInt64иSystem.Int64соответственно. Значение по умолчанию целочисленного типа эквивалентно литералу0.Типы
Singleзначений с плавающей запятой (4-байтовые с плавающей запятой) иDouble(8-байтовые с плавающей запятой). Эти типы сопоставляют сSystem.SingleиSystem.Doubleсоответственно. Значение по умолчанию типа с плавающей запятой эквивалентно литералу0.Тип
Decimal(десятичное десятичное значение 16 байтов), с которым сопоставляетсяSystem.Decimal. Значение десятичного значения по умолчанию эквивалентно литералу0D.BooleanТип значения, представляющий значение истины, обычно результат реляционной или логической операции. Литерал имеет типSystem.Boolean. ЗначениеBooleanпо умолчанию типа эквивалентно литералуFalse.Тип
Dateзначения, представляющий дату и (или) время и сопоставляется сSystem.DateTime. ЗначениеDateпо умолчанию типа эквивалентно литералу# 01/01/0001 12:00:00AM #.Тип
Charзначения, представляющий один символ Юникода и сопоставляется сSystem.Char. ЗначениеCharтипа по умолчанию эквивалентно выражениюChrW(0)константы.Ссылочный
Stringтип, представляющий последовательность символов Юникода и сопоставляется сSystem.String. Значением по умолчанию типаStringявляется значение NULL.
Перечисления
Перечисления — это типы значений, наследуемые от System.Enum и символьно представляющие набор значений одного из примитивных целочисленных типов.
EnumDeclaration
: Attributes? TypeModifier* 'Enum' Identifier
( 'As' NonArrayTypeName )? StatementTerminator
EnumMemberDeclaration+
'End' 'Enum' StatementTerminator
;
Для типа Eперечисления значение по умолчанию — это значение, созданное выражением CType(0, E).
Базовый тип перечисления должен быть целочисленным типом, который может представлять все значения перечислителя, определенные в перечислении. Если указан базовый тип, он должен быть Byte, SByteUShortShort, , UInteger, , Integer, ULong, Longили один из соответствующих типов в System пространстве имен. Если базовый тип явно не указан, используется Integerзначение по умолчанию.
В следующем примере объявляется перечисление с базовым типом Long:
Enum Color As Long
Red
Green
Blue
End Enum
Разработчик может использовать базовый тип Long, как в примере, чтобы включить использование значений, которые находятся в диапазоне, но не в диапазонеLongInteger, или сохранить этот параметр в будущем.
Элементы перечисления
Члены перечисления — это перечисленные значения, объявленные в перечислении, и члены, унаследованные от класса System.Enum.
Область элемента перечисления — это тело объявления перечисления. Это означает, что вне объявления перечисления элемент перечисления всегда должен быть квалифицирован (если тип не импортируется в пространство имен через импорт пространства имен).
Порядок объявления для объявлений элементов перечисления имеет значение, если значения константного выражения опущены. Элементы перечисления неявно имеют Public доступ только; модификаторы доступа не допускаются для объявлений членов перечисления.
EnumMemberDeclaration
: Attributes? Identifier ( Equals ConstantExpression )? StatementTerminator
;
Значения перечисления
Перечисленные значения в списке элементов перечисления объявляются как константы, типизированные как базовый тип перечисления, и они могут отображаться везде, где требуются константы. Определение элемента перечисления с = соответствующим элементом указывает значение, указанное константным выражением. Константное выражение должно иметь целочисленный тип, который неявно преобразуется в базовый тип и должен находиться в диапазоне значений, которые могут быть представлены базовым типом. В следующем примере возникает ошибка, так как константные значения 1.52.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
Ниже приведены причины для значений.
Значение перечисления автоматически присваивается значению
Red0(так как он не имеет инициализатора и является первым элементом значения перечисления).Значение
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.ArraySystem.EnumSystem.MulticastDelegate или.System.Delegate Универсальный класс не может быть производным от System.Attribute класса, наследуемого от него.
Каждый класс имеет ровно один прямой базовый класс, а цикличность в производных запрещена. Невозможно наследовать от NotInheritable класса, а домен специальных возможностей базового класса должен совпадать с или супермножеством домена специальных возможностей самого класса.
Члены класса
Члены класса состоят из членов, представленных объявлениями членов класса, и члены, унаследованные от прямого базового класса.
ClassMemberDeclaration
: NonModuleDeclaration
| EventMemberDeclaration
| VariableMemberDeclaration
| ConstantMemberDeclaration
| MethodMemberDeclaration
| PropertyMemberDeclaration
| ConstructorMemberDeclaration
| OperatorDeclaration
;
Объявление члена класса может иметь Public, Protected, FriendProtected Friendили Private доступ. Если объявление члена класса не включает модификатор доступа, объявление по умолчанию используется для Public доступа, если оно не является объявлением переменной. В этом случае он по умолчанию используется для Private доступа.
Область действия элемента класса — это тело класса, в котором происходит объявление члена, а также список ограничений этого класса (если он является универсальным и имеет ограничения). Если член имеет Friend доступ, его область расширяется до тела класса любого производного класса в той же программе или любой сборкеFriend, предоставленной доступом, и если член имеет PublicProtected, или 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 к . Если бы 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
Учитывая приведенное выше объявление, приведенные ниже операторы создают и Pointx инициализированы y до нуля.
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
Как правило, объявление элемента структуры может иметь PublicFriendтолько доступ или Private доступ, но при переопределении элементов, унаследованных отObject, Protected а Protected Friend также может использоваться доступ. Если объявление элемента структуры не включает модификатор доступа, объявление по умолчанию используется для 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
;
Как правило, объявление члена стандартного модуля может иметь PublicFriendтолько доступ или 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 является производным от класса и реализует оба IControl и ControlIDataBound:
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и ITextBoxIListBox.
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 даже если класс реализует IComboBox и 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
Предложение 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
Члены интерфейса с тем же именем, что и члены неявно теневых ObjectObject элементов. Только вложенные типы, методы, свойства и события могут быть членами интерфейса. Методы и свойства могут не содержать текст. Элементы интерфейса неявно 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) и IReadOnlyList(Of U) для любого U из них с расширением ссылочного преобразования.T
Массив имеет ранг , определяющий количество индексов, связанных с каждым элементом массива. Ранг массива определяет количество измерений массива. Например, массив с рангом одного называется одномерным массивом, а массив с рангом больше одного называется многомерным массивом.
В следующем примере создается одномерный массив целых значений, инициализирует элементы массива, а затем выводит каждый из них:
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
;
Ближайший эквивалент делегата на других языках является указателем функции, но в то время как указатель функции может ссылаться только Shared на функции, делегат может ссылаться как на методы экземпляра, так и на Shared них. В последнем случае делегат сохраняет не только ссылку на точку входа метода, но и ссылку на экземпляр объекта, с которым вызывается метод.
Объявление делегата 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 с элементами Test.C1 и 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
При объединении объявлений частичных типов по крайней мере один из объявлений должен иметь Partial модификатор, в противном случае результаты ошибки во время компиляции.
Примечание. Хотя можно указать только одно объявление среди многих частичных объявлений, лучше указать Partial его для всех частичных объявлений. В ситуации, когда одно частичное объявление отображается, но одно или несколько частичных объявлений скрыты (например, в случае расширения кода, созданного инструментом), можно оставить Partial модификатор вне видимого объявления, но указать его в скрытых объявлениях.
С помощью частичных объявлений можно объявлять только классы и структуры. При сопоставлении частичных объявлений при сопоставлении частичных объявлений с одинаковым именем считаются два класса с одинаковым именем, но разные числа параметров типа не считаются частичными объявлениями одного и того же времени. Частичные объявления могут указывать атрибуты, модификаторы классов, 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, наследующийся от Object и реализующий.System.IComparableSystem.IDisposablePublic Частичные Test2 объявления вызывают ошибку во время компиляции, так как одно из объявлений говорит, что это PublicTest2 и другой говорит, что это Test2Private.
Частичные типы с параметрами типа могут объявлять ограничения и дисперсию для параметров типа, но ограничения и дисперсии каждого частичного объявления должны соответствовать. Таким образом, ограничения и дисперсии являются особыми в том, что они не объединяются автоматически, как и другие модификаторы:
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 которому можно получить доступ только в контекстах, которые могут получить доступкак к Friend элементам, такиProtected к элементам. Однако нет способа выразить этот уровень специальных возможностей на языке, так как специальные Protected Friend возможности означает, что сущность может быть доступ кней в контексте, который может получить доступ ни FriendProtectedк членам, ни к членам.
Базовые, реализованные интерфейсы и члены созданных типов определяются путем замены предоставленных аргументов типа для каждого вхождения параметра типа в универсальном типе.
Открытые типы и закрытые типы
Созданный тип, для которого один или несколько аргументов типа являются параметрами типа содержащего типа или метода, называются открытым типом. Это связано с тем, что некоторые параметры типа типа по-прежнему не известны, поэтому фактическая форма типа еще не полностью известна. В отличие от этого, универсальный тип, аргументы которого являются всеми нетипизированными параметрами, называются закрытым типом. Форма закрытого типа всегда полностью известна. Рассмотрим пример.
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, представляющий тип void в .NET Framework, можно напрямую ссылаться только в GetType выражениях.
Типы System.RuntimeArgumentHandleи System.ArgIteratorSystem.TypedReference все могут содержать указатели в стек и поэтому не могут отображаться в куче .NET Framework. Поэтому их нельзя использовать как типы элементов массива, возвращаемые типы, типы полей, аргументы универсального типа, типы значений, типы ByRef параметров, тип преобразуемого Object значения в или System.ValueTypeцелевой объект вызова для членов Object экземпляра или System.ValueType, или, поднимаемый в закрытие.
Visual Basic language spec