형식 멤버는 스토리지 위치 및 실행 코드를 정의합니다. 메서드, 생성자, 이벤트, 상수, 변수 및 속성일 수 있습니다.
인터페이스 메서드 구현
메서드, 이벤트 및 속성은 인터페이스 멤버를 구현할 수 있습니다. 인터페이스 멤버를 구현하기 위해 멤버 선언은 키워드를 Implements 지정하고 하나 이상의 인터페이스 멤버를 나열합니다.
ImplementsClause
: ( 'Implements' ImplementsList )?
;
ImplementsList
: InterfaceMemberSpecifier ( Comma InterfaceMemberSpecifier )*
;
InterfaceMemberSpecifier
: NonArrayTypeName Period IdentifierOrKeyword
;
인터페이스 멤버를 구현하는 메서드 및 속성은 다른 멤버로 선언되거나 다른 멤버를 재정의하지 않는 한 암시적으로 NotOverridable 적용됩니다MustOverrideOverridable. 인터페이스 멤버 Shared를 구현하는 멤버에 대한 오류입니다. 멤버의 접근성은 인터페이스 멤버를 구현하는 기능에 영향을 주지 않습니다.
인터페이스 구현이 유효하려면 포함하는 형식의 구현 목록에서 호환되는 멤버를 포함하는 인터페이스의 이름을 지정해야 합니다. 호환되는 멤버는 서명이 구현 멤버의 서명과 일치하는 멤버입니다. 제네릭 인터페이스가 구현되는 경우 호환성을 확인할 때 Implements 절에 제공된 형식 인수가 서명으로 대체됩니다. 다음은 그 예입니다.
Interface I1(Of T)
Sub F(x As T)
End Interface
Class C1
Implements I1(Of Integer)
Sub F(x As Integer) Implements I1(Of Integer).F
End Sub
End Class
Class C2(Of U)
Implements I1(Of U)
Sub F(x As U) Implements I1(Of U).F
End Sub
End Class
대리자 형식을 사용하여 선언된 이벤트가 인터페이스 이벤트를 구현하는 경우 호환되는 이벤트는 기본 대리자 형식이 동일한 이벤트입니다. 그렇지 않으면 이벤트가 구현하는 인터페이스 이벤트의 대리자 형식을 사용합니다. 이러한 이벤트가 여러 인터페이스 이벤트를 구현하는 경우 모든 인터페이스 이벤트에는 동일한 기본 대리자 형식이 있어야 합니다. 다음은 그 예입니다.
Interface ClickEvents
Event LeftClick(x As Integer, y As Integer)
Event RightClick(x As Integer, y As Integer)
End Interface
Class Button
Implements ClickEvents
' OK. Signatures match, delegate type = ClickEvents.LeftClickHandler.
Event LeftClick(x As Integer, y As Integer) _
Implements ClickEvents.LeftClick
' OK. Signatures match, delegate type = ClickEvents.RightClickHandler.
Event RightClick(x As Integer, y As Integer) _
Implements ClickEvents.RightClick
End Class
Class Label
Implements ClickEvents
' Error. Signatures match, but can't be both delegate types.
Event Click(x As Integer, y As Integer) _
Implements ClickEvents.LeftClick, ClickEvents.RightClick
End Class
구현 목록의 인터페이스 멤버는 형식 이름, 마침표 및 식별자를 사용하여 지정됩니다. 형식 이름은 구현 목록의 인터페이스이거나 구현 목록에 있는 인터페이스의 기본 인터페이스여야 하며 식별자는 지정된 인터페이스의 멤버여야 합니다. 단일 멤버는 둘 이상의 일치하는 인터페이스 멤버를 구현할 수 있습니다.
Interface ILeft
Sub F()
End Interface
Interface IRight
Sub F()
End Interface
Class Test
Implements ILeft, IRight
Sub F() Implements ILeft.F, IRight.F
End Sub
End Class
구현 중인 인터페이스 멤버가 여러 인터페이스 상속으로 인해 명시적으로 구현된 모든 인터페이스에서 사용할 수 없는 경우 구현 멤버는 멤버를 사용할 수 있는 기본 인터페이스를 명시적으로 참조해야 합니다. 예를 들어 멤버M를 포함하고 상속되는 I1I2경우 I1 구현하는 I3 형식이 구현 I1.M 되고 I2.M.I2I3 인터페이스 그림자가 상속된 멤버를 곱한 경우 구현 형식은 상속된 멤버와 멤버를 섀도링하는 멤버를 구현해야 합니다.
Interface ILeft
Sub F()
End Interface
Interface IRight
Sub F()
End Interface
Interface ILeftRight
Inherits ILeft, IRight
Shadows Sub F()
End Interface
Class Test
Implements ILeftRight
Sub LeftF() Implements ILeft.F
End Sub
Sub RightF() Implements IRight.F
End Sub
Sub LeftRightF() Implements ILeftRight.F
End Sub
End Class
구현할 인터페이스 멤버의 포함 인터페이스가 제네릭인 경우 구현되는 인터페이스와 동일한 형식 인수를 제공해야 합니다. 다음은 그 예입니다.
Interface I1(Of T)
Function F() As T
End Interface
Class C1
Implements I1(Of Integer)
Implements I1(Of Double)
Function F1() As Integer Implements I1(Of Integer).F
End Function
Function F2() As Double Implements I1(Of Double).F
End Function
' Error: I1(Of String) is not implemented by C1
Function F3() As String Implements I1(Of String).F
End Function
End Class
Class C2(Of U)
Implements I1(Of U)
Function F() As U Implements I1(Of U).F
End Function
End Class
메서드
메서드는 프로그램의 실행 문을 포함합니다.
MethodMemberDeclaration
: MethodDeclaration
| ExternalMethodDeclaration
;
InterfaceMethodMemberDeclaration
: InterfaceMethodDeclaration
;
MethodDeclaration
: SubDeclaration
| MustOverrideSubDeclaration
| FunctionDeclaration
| MustOverrideFunctionDeclaration
;
InterfaceMethodDeclaration
: InterfaceSubDeclaration
| InterfaceFunctionDeclaration
;
SubSignature
: 'Sub' Identifier TypeParameterList?
( OpenParenthesis ParameterList? CloseParenthesis )?
;
FunctionSignature
: 'Function' Identifier TypeParameterList?
( OpenParenthesis ParameterList? CloseParenthesis )?
( 'As' Attributes? TypeName )?
;
SubDeclaration
: Attributes? ProcedureModifier* SubSignature
HandlesOrImplements? LineTerminator
Block
'End' 'Sub' StatementTerminator
;
MustOverrideSubDeclaration
: Attributes? MustOverrideProcedureModifier+ SubSignature
HandlesOrImplements? StatementTerminator
;
InterfaceSubDeclaration
: Attributes? InterfaceProcedureModifier* SubSignature StatementTerminator
;
FunctionDeclaration
: Attributes? ProcedureModifier* FunctionSignature
HandlesOrImplements? LineTerminator
Block
'End' 'Function' StatementTerminator
;
MustOverrideFunctionDeclaration
: Attributes? MustOverrideProcedureModifier+ FunctionSignature
HandlesOrImplements? StatementTerminator
;
InterfaceFunctionDeclaration
: Attributes? InterfaceProcedureModifier* FunctionSignature StatementTerminator
;
ProcedureModifier
: AccessModifier | 'Shadows' | 'Shared' | 'Overridable' | 'NotOverridable' | 'Overrides'
| 'Overloads' | 'Partial' | 'Iterator' | 'Async'
;
MustOverrideProcedureModifier
: ProcedureModifier
| 'MustOverride'
;
InterfaceProcedureModifier
: 'Shadows' | 'Overloads'
;
HandlesOrImplements
: HandlesClause
| ImplementsClause
;
선택적 매개 변수 목록과 선택적 반환 값이 있는 메서드는 공유되거나 공유되지 않습니다. 공유 메서드는 클래스 또는 클래스의 인스턴스를 통해 액세스됩니다. 인스턴스 메서드라고도 하는 공유되지 않은 메서드는 클래스의 인스턴스를 통해 액세스됩니다. 다음 예제에서는 여러 공유 메서드(Clone및) 및 Flip여러 인스턴스 메서드(Push및Pop)가 있는 클래스 Stack 를 보여 줍니다ToString.
Public Class Stack
Public Shared Function Clone(s As Stack) As Stack
...
End Function
Public Shared Function Flip(s As Stack) As Stack
...
End Function
Public Function Pop() As Object
...
End Function
Public Sub Push(o As Object)
...
End Sub
Public Overrides Function ToString() As String
...
End Function
End Class
Module Test
Sub Main()
Dim s As Stack = New Stack()
Dim i As Integer
While i < 10
s.Push(i)
End While
Dim flipped As Stack = Stack.Flip(s)
Dim cloned As Stack = Stack.Clone(s)
Console.WriteLine("Original stack: " & s.ToString())
Console.WriteLine("Flipped stack: " & flipped.ToString())
Console.WriteLine("Cloned stack: " & cloned.ToString())
End Sub
End Module
메서드를 오버로드할 수 있습니다. 즉, 고유한 서명이 있는 한 여러 메서드의 이름이 같을 수 있습니다. 메서드의 서명은 해당 매개 변수의 수와 형식으로 구성됩니다. 메서드의 시그니처에는 특히 Optional, ByRef 또는 ParamArray와 같은 반환 형식 또는 매개 변수 한정자가 포함되지 않습니다. 다음 예제에서는 오버로드 수가 많은 클래스를 보여 줍니다.
Module Test
Sub F()
Console.WriteLine("F()")
End Sub
Sub F(o As Object)
Console.WriteLine("F(Object)")
End Sub
Sub F(value As Integer)
Console.WriteLine("F(Integer)")
End Sub
Sub F(a As Integer, b As Integer)
Console.WriteLine("F(Integer, Integer)")
End Sub
Sub F(values() As Integer)
Console.WriteLine("F(Integer())")
End Sub
Sub G(s As String, Optional s2 As String = 5)
Console.WriteLine("G(String, Optional String")
End Sub
Sub G(s As String)
Console.WriteLine("G(String)")
End Sub
Sub Main()
F()
F(1)
F(CType(1, Object))
F(1, 2)
F(New Integer() { 1, 2, 3 })
G("hello")
G("hello", "world")
End Sub
End Module
프로그램의 출력은 다음과 같습니다.
F()
F(Integer)
F(Object)
F(Integer, Integer)
F(Integer())
G(String)
G(String, Optional String)
선택적 매개 변수에서만 다른 오버로드는 라이브러리의 "버전 관리"에 사용할 수 있습니다. 예를 들어 라이브러리의 v1에는 선택적 매개 변수가 있는 함수가 포함될 수 있습니다.
Sub fopen(fileName As String, Optional accessMode as Integer = 0)
그런 다음 라이브러리의 v2는 또 다른 선택적 매개 변수 "password"를 추가하려고 하며 원본 호환성을 손상하지 않고(v1을 대상으로 하는 데 사용된 애플리케이션을 다시 컴파일할 수 있음) 이진 호환성을 손상하지 않고 추가하려고 합니다(따라서 v1을 참조하는 데 사용된 애플리케이션은 이제 다시 컴파일하지 않고 v2를 참조할 수 있음). v2의 모양은 다음과 같습니다.
Sub fopen(file As String, mode as Integer)
Sub fopen(file As String, Optional mode as Integer = 0, Optional pword As String = "")
공용 API의 선택적 매개 변수는 CLS 규격이 아닙니다. 그러나 적어도 Visual Basic 및 C#4 및 F#에서 사용할 수 있습니다.
일반, 비동기 및 반복기 메서드 선언
메서드에는 값을 반환하지 않는 서브루틴과 함수의 두 가지 유형이 있습니다. 메서드가 인터페이스에 정의되어 있거나 MustOverride 한정자가 있는 경우에만 메서드의 본문과 End 구문을 생략할 수 있습니다. 함수에 반환 형식을 지정하지 않고 엄격한 의미 체계를 사용하는 경우 컴파일 시간 오류가 발생합니다. 그렇지 않으면 형식이 암시적으로 Object 또는 메서드의 형식 문자 형식입니다. 메서드의 반환 형식 및 매개 변수 형식의 접근성 도메인은 메서드 자체의 접근성 도메인과 동일하거나 상위 집합이어야 합니다.
일반 메서드는 한정자도 없는 AsyncIterator 메서드입니다. 서브루틴 또는 함수일 수 있습니다. 섹션 일반 메서드는 일반 메서드가 호출될 때 발생하는 작업에 대해 자세히 설명합니다.
반복기 메서드는 한 Iterator 정자와 한정자가 없는 Async 메서드입니다. 함수여야 하며 해당 반환 형식은 IEnumeratorIEnumerableIEnumerable(Of T)IEnumerator(Of T) 또는 일부 T함수여야 하며 매개 변수가 없어야 ByRef 합니다. 섹션 반복기 메서드 는 반복기 메서드가 호출될 때 발생하는 작업에 대해 자세히 설명합니다.
비동기 메서드는 한 Async 정자와 한정자가 없는 Iterator 메서드입니다. 서브루틴이거나 반환 형식 Task 이 있는 함수이거나 Task(Of T) 일부 T함수여야 하며 매개 변수가 없어야 ByRef 합니다. 섹션 비동기 메서드는 비동기 메서드가 호출될 때 발생하는 작업에 대해 자세히 설명합니다.
메서드가 이러한 세 가지 메서드 종류 중 하나가 아닌 경우 컴파일 시간 오류입니다.
서브루틴 및 함수 선언은 시작 문과 끝 문이 각각 논리 줄의 시작 부분에서 시작되어야 한다는 측면에서 특별합니다. 또한 비 서브MustOverride 루틴 또는 함수 선언의 본문은 논리 줄의 시작 부분에서 시작해야 합니다. 다음은 그 예입니다.
Module Test
' Illegal: Subroutine doesn't start the line
Public x As Integer : Sub F() : End Sub
' Illegal: First statement doesn't start the line
Sub G() : Console.WriteLine("G")
End Sub
' Illegal: End Sub doesn't start the line
Sub H() : End Sub
End Module
외부 메서드 선언
외부 메서드 선언은 프로그램 외부에 구현이 제공되는 새 메서드를 도입합니다.
ExternalMethodDeclaration
: ExternalSubDeclaration
| ExternalFunctionDeclaration
;
ExternalSubDeclaration
: Attributes? ExternalMethodModifier* 'Declare' CharsetModifier? 'Sub'
Identifier LibraryClause AliasClause?
( OpenParenthesis ParameterList? CloseParenthesis )? StatementTerminator
;
ExternalFunctionDeclaration
: Attributes? ExternalMethodModifier* 'Declare' CharsetModifier? 'Function'
Identifier LibraryClause AliasClause?
( OpenParenthesis ParameterList? CloseParenthesis )?
( 'As' Attributes? TypeName )?
StatementTerminator
;
ExternalMethodModifier
: AccessModifier
| 'Shadows'
| 'Overloads'
;
CharsetModifier
: 'Ansi' | 'Unicode' | 'Auto'
;
LibraryClause
: 'Lib' StringLiteral
;
AliasClause
: 'Alias' StringLiteral
;
외부 메서드 선언은 실제 구현을 제공하지 않으므로 메서드 본문이나 End 구문이 없습니다. 외부 메서드는 암시적으로 공유되고 형식 매개 변수가 없을 수 있으며 이벤트를 처리하거나 인터페이스 멤버를 구현하지 않을 수 있습니다. 함수에 반환 형식을 지정하지 않고 엄격한 의미 체계를 사용하는 경우 컴파일 시간 오류가 발생합니다. 그렇지 않으면 형식이 암시적으로 Object 또는 메서드의 형식 문자 형식입니다. 외부 메서드의 반환 형식 및 매개 변수 형식의 접근성 도메인은 외부 메서드 자체의 접근성 도메인과 동일하거나 상위 집합이어야 합니다.
외부 메서드 선언의 라이브러리 절은 메서드를 구현하는 외부 파일의 이름을 지정합니다. 선택적 별칭 절은 외부 파일에 있는 메서드의 숫자 서수(문자 앞에 접두 # 사) 또는 이름을 지정하는 문자열입니다. 외부 메서드를 호출하는 동안 문자열을 마샬링하는 데 사용되는 문자 집합을 제어하는 단일 문자 집합 한정자를 지정할 수도 있습니다.
Unicode 한정자는 모든 문자열을 유니코드 값으로 마샬링하고, Ansi 한정자는 모든 문자열을 ANSI 값으로 마샬링하고Auto, 한정자는 메서드 이름 또는 지정된 경우 별칭 이름을 기반으로 .NET Framework 규칙에 따라 문자열을 마샬링합니다. 한정자를 지정하지 않으면 기본값은 .입니다 Ansi.
지정한 Unicode 경우 Ansi 메서드 이름은 수정 없이 외부 파일에서 조회됩니다. 지정된 경우 Auto 메서드 이름 조회는 플랫폼에 따라 달라집니다. 플랫폼이 ANSI(예: Windows 95, Windows 98, Windows ME)로 간주되는 경우 메서드 이름은 수정 없이 조회됩니다. 조회가 실패하면 추가 A 되고 조회가 다시 시도됩니다. 플랫폼이 유니코드(예: Windows NT, Windows 2000, Windows XP)로 간주되는 경우 a W 가 추가되고 이름이 조회됩니다. 조회가 실패하면 .W 다음은 그 예입니다.
Module Test
' All platforms bind to "ExternSub".
Declare Ansi Sub ExternSub Lib "ExternDLL" ()
' All platforms bind to "ExternSub".
Declare Unicode Sub ExternSub Lib "ExternDLL" ()
' ANSI platforms: bind to "ExternSub" then "ExternSubA".
' Unicode platforms: bind to "ExternSubW" then "ExternSub".
Declare Auto Sub ExternSub Lib "ExternDLL" ()
End Module
외부 메서드에 전달되는 데이터 형식은 한 가지 예외를 제외하고 .NET Framework 데이터 마샬링 규칙에 따라 마샬링됩니다. 값으로 전달되는 문자열 변수(즉, ByVal x As String)는 OLE Automation BSTR 형식으로 마샬링되고 외부 메서드의 BSTR 변경 내용은 문자열 인수에 다시 반영됩니다. 외부 메서드의 형식 String 이 변경 가능하고 이 특수 마샬링이 해당 동작을 모방하기 때문입니다. 참조(예 ByRef x As String: )로 전달되는 문자열 매개 변수는 OLE Automation BSTR 형식에 대한 포인터로 마샬링됩니다. 매개 변수에 특성을 지정하여 이러한 특수 동작을 재정의 System.Runtime.InteropServices.MarshalAsAttribute 할 수 있습니다.
이 예제에서는 외부 메서드를 사용하는 방법을 보여 줍니다.
Class Path
Declare Function CreateDirectory Lib "kernel32" ( _
Name As String, sa As SecurityAttributes) As Boolean
Declare Function RemoveDirectory Lib "kernel32" ( _
Name As String) As Boolean
Declare Function GetCurrentDirectory Lib "kernel32" ( _
BufSize As Integer, Buf As String) As Integer
Declare Function SetCurrentDirectory Lib "kernel32" ( _
Name As String) As Boolean
End Class
재정의 가능한 메서드
Overridable 한정자는 메서드를 재정의할 수 있음을 나타냅니다.
Overrides 한정자는 메서드가 동일한 시그니처가 있는 기본 형식 재정의 가능한 메서드를 재정의한다는 것을 나타냅니다.
NotOverridable 한정자는 재정의 가능한 메서드를 더 이상 재정의할 수 없음을 나타냅니다.
MustOverride 한정자는 파생 클래스에서 메서드를 재정의해야 임을 나타냅니다.
이러한 한정자의 특정 조합은 유효하지 않습니다.
Overridable는NotOverridable상호 배타적이며 결합할 수 없습니다.MustOverride은Overridable(따라서 지정할 수 없음)을 의미하며 , 와 결합NotOverridable할 수 없습니다.NotOverridable와 결합OverridableMustOverride할 수 없거나 결합해야Overrides합니다.Overrides은Overridable(따라서 지정할 수 없음)을 의미하며 , 와 결합MustOverride할 수 없습니다.
재정의 가능한 메서드에 대한 추가 제한 사항도 있습니다.
메서드는
MustOverride메서드 본문 또는End구문을 포함할 수 없으며 다른 메서드를 재정의할 수 없으며 클래스에MustInherit만 나타날 수 있습니다.메서드가 지정
Overrides하고 재정의할 일치하는 기본 메서드가 없는 경우 컴파일 시간 오류가 발생합니다. 재정의 메서드는 지정Shadows하지 않을 수 있습니다.재정의 메서드의 접근성 도메인이 재정의되는 메서드의 접근성 도메인과 같지 않으면 메서드가 다른 메서드를 재정의하지 않을 수 있습니다. 한 가지 예외는 액세스 권한이 없는 다른 어셈블리의 메서드를 재정의
Friend하는Protected Friend메서드가 지정Protected해야 한다는 것입니다(아님Protected Friend).Private메서드는OverridableNotOverridableMustOverride다른 메서드를 재정의하지 않거나 재정의할 수도 없습니다.클래스의
NotInheritable메서드를 선언Overridable하거나MustOverride.
다음 예제에서는 재정의 가능한 메서드와 재정의할 수 없는 메서드 간의 차이점을 보여 줍니다.
Class Base
Public Sub F()
Console.WriteLine("Base.F")
End Sub
Public Overridable Sub G()
Console.WriteLine("Base.G")
End Sub
End Class
Class Derived
Inherits Base
Public Shadows Sub F()
Console.WriteLine("Derived.F")
End Sub
Public Overrides Sub G()
Console.WriteLine("Derived.G")
End Sub
End Class
Module Test
Sub Main()
Dim d As Derived = New Derived()
Dim b As Base = d
b.F()
d.F()
b.G()
d.G()
End Sub
End Module
이 예제에서 클래스 Base 는 메서드와 메서드 FG를 Overridable 소개합니다. 클래스 Derived 는 새 메서드를 도입하여 상속된 메서드 F를 섀도링하고 상속된 F메서드 G를 재정의합니다. 이 예제에서는 다음 출력을 생성합니다.
Base.F
Derived.F
Derived.G
Derived.G
b.G()문은 Derived.G가 아니라 Base.G을(를) 호출합니다. 이는 인스턴스의 컴파일 시간 형식( Derived즉)이 아닌 인스턴스의 런타임 형식이 호출할 실제 메서드 구현을 결정하기 때문입니다 Base.
공유 메서드
Shared 한정자는 메서드가 공유 메서드임을 나타냅니다. 공유 메서드는 형식의 특정 인스턴스에서 작동하지 않으며 형식의 특정 인스턴스가 아닌 형식에서 직접 호출될 수 있습니다. 그러나 인스턴스를 사용하여 공유 메서드를 한정하는 것은 유효합니다. 또는 공유 메서드를 참조하는 MeMyClassMyBase 것은 유효하지 않습니다. 공유 메서드가 OverridableNotOverridable아니거나 MustOverride메서드를 재정의하지 않을 수 있습니다. 표준 모듈 및 인터페이스에 정의된 메서드는 암시적으로 Shared 이미 있으므로 지정Shared하지 않을 수 있습니다.
한정자가 없는 구조체 또는 클래스에 Shared 선언된 메서드는 인스턴스 메서드입니다. 인스턴스 메서드는 지정된 형식의 인스턴스에서 작동합니다. 인스턴스 메서드는 형식의 인스턴스를 통해서만 호출할 수 있으며 식을 통해 Me 인스턴스를 참조할 수 있습니다.
다음 예제에서는 공유 및 인스턴스 멤버에 액세스하기 위한 규칙을 보여 줍니다.
Class Test
Private x As Integer
Private Shared y As Integer
Sub F()
x = 1 ' Ok, same as Me.x = 1.
y = 1 ' Ok, same as Test.y = 1.
End Sub
Shared Sub G()
x = 1 ' Error, cannot access Me.x.
y = 1 ' Ok, same as Test.y = 1.
End Sub
Shared Sub Main()
Dim t As Test = New Test()
t.x = 1 ' Ok.
t.y = 1 ' Ok.
Test.x = 1 ' Error, cannot access instance member through type.
Test.y = 1 ' Ok.
End Sub
End Class
메서드 F 는 인스턴스 함수 멤버에서 식별자를 사용하여 인스턴스 멤버와 공유 멤버 모두에 액세스할 수 있음을 보여 줍니다. 메서드 G 는 공유 함수 멤버에서 식별자를 통해 인스턴스 멤버에 액세스하는 것은 오류임을 보여 줍니다. 메서드 Main 는 멤버 액세스 식에서 인스턴스 멤버를 통해 액세스해야 하지만 공유 멤버는 형식 또는 인스턴스를 통해 액세스할 수 있음을 보여 줍니다.
메서드 매개 변수
매개 변수는 메서드 내부 및 외부로 정보를 전달하는 데 사용할 수 있는 변수입니다. 메서드의 매개 변수는 쉼표로 구분된 하나 이상의 매개 변수로 구성된 메서드의 매개 변수 목록에 의해 선언됩니다.
ParameterList
: Parameter ( Comma Parameter )*
;
Parameter
: Attributes? ParameterModifier* ParameterIdentifier ( 'As' TypeName )?
( Equals ConstantExpression )?
;
ParameterModifier
: 'ByVal' | 'ByRef' | 'Optional' | 'ParamArray'
;
ParameterIdentifier
: Identifier IdentifierModifiers
;
매개 변수에 대해 형식을 지정하지 않고 엄격한 의미 체계를 사용하는 경우 컴파일 시간 오류가 발생합니다. 그렇지 않으면 기본 형식이 Object 거나 매개 변수의 형식 문자 형식입니다. 허용되는 의미 체계에서도 하나의 매개 변수에 절이 As 포함된 경우 모든 매개 변수가 형식을 지정해야 합니다.
매개 변수는 각각 한정자ByValByRefOptional, 및 ParamArray매개 변수에 의해 값, 참조, 선택적 또는 paramarray 매개 변수로 지정됩니다. 지정 ByRefByVal 하지 않거나 기본값을 지정하지 않는 매개 변수입니다 ByVal.
매개 변수 이름은 메서드의 전체 본문으로 범위가 지정되며 항상 공개적으로 액세스할 수 있습니다. 메서드 호출은 해당 호출과 관련된 매개 변수의 복사본을 만들고 호출의 인수 목록은 새로 만든 매개 변수에 값 또는 변수 참조를 할당합니다. 외부 메서드 선언 및 대리자 선언에는 본문이 없으므로 매개 변수 목록에서 중복 매개 변수 이름이 허용되지만 권장되지 않습니다.
식별자 뒤에 nullable 이름 한정자가 ? 옵니다. null 허용임을 나타내고 배열 이름 한정자를 사용하여 배열임을 나타낼 수도 있습니다. 결합될 수 있습니다(예: "ByVal x?() As Integer"). 명시적 배열 범위를 사용할 수 없습니다. 또한 nullable 이름 한정자가 있으면 절이 As 있어야 합니다.
값 매개 변수
값 매개 변수는 명시적 ByVal 한정자를 사용하여 선언됩니다. 한 ByVal 정자를 사용하는 ByRef 경우 한정자를 지정하지 않을 수 있습니다. 값 매개 변수는 매개 변수가 속한 멤버를 호출하여 존재하게 되며 호출에 지정된 인수의 값으로 초기화됩니다. 멤버가 반환되면 값 매개 변수가 더 이상 존재하지 않습니다.
메서드는 값 매개 변수에 새 값을 할당할 수 있습니다. 이러한 할당은 값 매개 변수로 표시되는 로컬 스토리지 위치에만 영향을 줍니다. 메서드 호출에 지정된 실제 인수에는 영향을 주지 않습니다.
값 매개 변수는 인수 값이 메서드에 전달되고 매개 변수 수정이 원래 인수에 영향을 주지 않는 경우에 사용됩니다. 값 매개 변수는 해당 인수의 변수와 구별되는 자체 변수를 참조합니다. 이 변수는 해당 인수의 값을 복사하여 초기화됩니다. 다음 예제에서는 값 매개 변수가 있는 p메서드 F 를 보여줍니다.
Module Test
Sub F(p As Integer)
Console.WriteLine("p = " & p)
p += 1
End Sub
Sub Main()
Dim a As Integer = 1
Console.WriteLine("pre: a = " & a)
F(a)
Console.WriteLine("post: a = " & a)
End Sub
End Module
이 예제에서는 값 매개 변수 p 가 수정되더라도 다음 출력을 생성합니다.
pre: a = 1
p = 1
post: a = 1
참조 매개 변수
참조 매개 변수는 한정자를 사용하여 선언된 매개 변수입니다 ByRef .
ByRef 한정자를 지정 ByVal 하면 한정자를 사용할 수 없습니다. 참조 매개 변수는 새 스토리지 위치를 만들지 않습니다. 대신 참조 매개 변수는 메서드 또는 생성자 호출에서 인수로 지정된 변수를 나타냅니다. 개념적으로 참조 매개 변수의 값은 항상 기본 변수와 동일합니다.
참조 매개 변수는 별칭 또는 복사 복사를 통해 두 가지 모드로 작동합니다.
별칭. 참조 매개 변수는 매개 변수가 호출자 제공 인수의 별칭 역할을 할 때 사용됩니다. 참조 매개 변수 자체는 변수를 정의하는 것이 아니라 해당 인수의 변수를 참조합니다. 참조 매개 변수를 직접 수정하고 해당 인수에 즉시 영향을 줍니다. 다음 예제에서는 두 개의 참조 매개 변수가 있는 메서드 Swap 를 보여줍니다.
Module Test
Sub Swap(ByRef a As Integer, ByRef b As Integer)
Dim t As Integer = a
a = b
b = t
End Sub
Sub Main()
Dim x As Integer = 1
Dim y As Integer = 2
Console.WriteLine("pre: x = " & x & ", y = " & y)
Swap(x, y)
Console.WriteLine("post: x = " & x & ", y = " & y)
End Sub
End Module
프로그램의 출력은 다음과 같습니다.
pre: x = 1, y = 2
post: x = 2, y = 1
클래스에서 메서드 Swap 를 호출하는 경우 를 a 나타내 x, 고 b 나타냅니다y.Main 따라서 호출은 x과 y의 값을 서로 교환하는 효과가 있습니다.
참조 매개 변수를 사용하는 메서드에서는 여러 이름이 동일한 스토리지 위치를 나타낼 수 있습니다.
Module Test
Private s As String
Sub F(ByRef a As String, ByRef b As String)
s = "One"
a = "Two"
b = "Three"
End Sub
Sub G()
F(s, s)
End Sub
End Module
예제에서 메서드 FG 호출은 둘 다 a 에 대한 참조 s 를 전달합니다b. 따라서 해당 호출의 경우 이름 s및 ab 모든 항목은 동일한 스토리지 위치를 참조하며, 세 가지 할당은 모두 인스턴스 변수s를 수정합니다.
복사-다시 복사. 참조 매개 변수에 전달되는 변수의 형식이 참조 매개 변수의 형식과 호환되지 않거나 변수가 아닌(예: 속성)이 참조 매개 변수에 인수로 전달되거나 호출이 런타임에 바인딩된 경우 임시 변수가 할당되어 참조 매개 변수에 전달됩니다. 전달되는 값은 메서드가 호출되기 전에 이 임시 변수로 복사되고 메서드가 반환될 때 원래 변수(있는 경우 및 쓰기 가능한 경우)로 다시 복사됩니다. 따라서 참조 매개 변수는 전달되는 변수의 정확한 스토리지에 대한 참조를 반드시 포함하지 않을 수 있으며, 메서드가 종료될 때까지 참조 매개 변수에 대한 변경 내용이 변수에 반영되지 않을 수 있습니다. 다음은 그 예입니다.
Class Base
End Class
Class Derived
Inherits Base
End Class
Module Test
Sub F(ByRef b As Base)
b = New Base()
End Sub
Property G() As Base
Get
End Get
Set
End Set
End Property
Sub Main()
Dim d As Derived
F(G) ' OK.
F(d) ' Throws System.InvalidCastException after F returns.
End Sub
End Module
첫 번째 호출의 F경우 임시 변수가 만들어지고 속성 G 값이 할당되어 전달 F됩니다. 반환 시 F임시 변수의 값이 .의 G속성에 다시 할당됩니다. 두 번째 경우 다른 임시 변수가 만들어지고 값 d 이 할당되어 전달 F됩니다. 반환할 F때 임시 변수의 값은 변수 Derived의 형식으로 다시 캐스팅되고 할당됩니다 d. 다시 전달되는 값을 캐스팅할 수 없으므로 Derived런타임에 예외가 throw됩니다.
선택적 매개 변수
선택적 매개 변수는 한정자를 사용하여 Optional 선언됩니다. 정식 매개 변수 목록에서 선택적 매개 변수를 따르는 매개 변수도 선택적이어야 합니다. 다음 매개 변수에서 Optional 한정자를 지정하지 않으면 컴파일 시간 오류가 트리거됩니다. 일부 형식 nullable 형식 또는 nullable이 아닌 형식 T?T 의 선택적 매개 변수는 인수가 지정되지 않은 경우 기본값으로 사용할 상수 식을 e 지정해야 합니다. Object 형식으로 Nothing 계산되는 경우 e매개 변수 형식의 기본값이 매개 변수의 기본값으로 사용됩니다. 그렇지 않으면 CType(e, T) 상수 식이어야 하며 매개 변수의 기본값으로 사용됩니다.
선택적 매개 변수는 매개 변수의 이니셜라이저가 유효한 유일한 상황입니다. 초기화는 항상 메서드 본문 자체가 아니라 호출 식의 일부로 수행됩니다.
Module Test
Sub F(x As Integer, Optional y As Integer = 20)
Console.WriteLine("x = " & x & ", y = " & y)
End Sub
Sub Main()
F(10)
F(30,40)
End Sub
End Module
프로그램의 출력은 다음과 같습니다.
x = 10, y = 20
x = 30, y = 40
선택적 매개 변수는 대리자 또는 이벤트 선언이나 람다 식에서 지정할 수 없습니다.
ParamArray 매개 변수
ParamArray 매개 변수는 한정자를 사용하여 ParamArray 선언됩니다.
ParamArray 한정자가 있는 ByVal 경우 한정자를 지정해야 하며 다른 매개 변수는 한정자를 사용할 ParamArray 수 없습니다. 매개 변수의 형식은 ParamArray 1차원 배열이어야 하며 매개 변수 목록의 마지막 매개 변수여야 합니다.
ParamArray 매개 변수는 형식의 확정되지 않은 개수의 매개 변수를 ParamArray나타냅니다. 메서드 자체 ParamArray 내에서 매개 변수는 선언된 형식으로 처리되며 특별한 의미 체계가 없습니다.
ParamArray 매개 변수는 암시적으로 선택 사항이며, 기본값은 해당 형식의 빈 1차원 배열입니다ParamArray.
메서드 ParamArray 호출의 두 가지 방법 중 하나로 인수를 지정할 수 있습니다.
지정된
ParamArray인수는 형식으로 확장되는 형식의 단일 식일 수 있습니다ParamArray. 이 경우ParamArray값 매개 변수처럼 정확하게 작동합니다.또는 호출에서 0개 이상의 인수를
ParamArray지정할 수 있습니다. 여기서 각 인수는 암시적으로 요소 형식으로 변환할 수 있는 형식의ParamArray식입니다. 이 경우 호출은 인수 수에 해당하는 길이가 있는 형식의ParamArray인스턴스를 만들고, 지정된 인수 값을 사용하여 배열 인스턴스의 요소를 초기화하고, 새로 만든 배열 인스턴스를 실제 인수로 사용합니다.
호출 ParamArray 에서 가변 개수의 인수를 허용하는 경우를 제외하고 다음 예제와 같이 동일한 형식의 값 매개 변수와 정확히 동일합니다.
Module Test
Sub F(ParamArray args() As Integer)
Dim i As Integer
Console.Write("Array contains " & args.Length & " elements:")
For Each i In args
Console.Write(" " & i)
Next i
Console.WriteLine()
End Sub
Sub Main()
Dim a As Integer() = { 1, 2, 3 }
F(a)
F(10, 20, 30, 40)
F()
End Sub
End Module
이 예제에서는 출력을 생성합니다.
Array contains 3 elements: 1 2 3
Array contains 4 elements: 10 20 30 40
Array contains 0 elements:
첫 번째 호출 F 은 단순히 배열 a 을 값 매개 변수로 전달합니다. 두 번째 호출 F 은 지정된 요소 값을 사용하여 4개 요소 배열을 자동으로 만들고 해당 배열 인스턴스를 값 매개 변수로 전달합니다. 마찬가지로 세 번째 호출 F 은 0 요소 배열을 만들고 해당 인스턴스를 값 매개 변수로 전달합니다. 두 번째 및 세 번째 호출은 쓰기와 정확히 동일합니다.
F(New Integer() {10, 20, 30, 40})
F(New Integer() {})
ParamArray 대리자 또는 이벤트 선언에서 매개 변수를 지정할 수 없습니다.
이벤트 처리
메서드는 인스턴스 또는 공유 변수의 개체에 의해 발생하는 이벤트를 선언적으로 처리할 수 있습니다. 이벤트를 처리하기 위해 메서드 선언은 키워드를 Handles 지정하고 하나 이상의 이벤트를 나열합니다.
HandlesClause
: ( 'Handles' EventHandlesList )?
;
EventHandlesList
: EventMemberSpecifier ( Comma EventMemberSpecifier )*
;
EventMemberSpecifier
: Identifier Period IdentifierOrKeyword
| 'MyBase' Period IdentifierOrKeyword
| 'MyClass' Period IdentifierOrKeyword
| 'Me' Period IdentifierOrKeyword
;
목록의 Handles 이벤트는 마침표로 구분된 두 개의 식별자에 의해 지정됩니다.
첫 번째 식별자는 한정자 또는 또는 키워드를 지정
WithEvents하는 포함 형식의 인스턴스 또는MyBaseMyClassMe공유 변수여야 합니다. 그렇지 않으면 컴파일 시간 오류가 발생합니다. 이 변수에는 이 메서드에서 처리하는 이벤트를 발생시키는 개체가 포함됩니다.두 번째 식별자는 첫 번째 식별자 형식의 멤버를 지정해야 합니다. 멤버는 이벤트여야 하며 공유할 수 있습니다. 첫 번째 식별자에 대해 공유 변수를 지정하는 경우 이벤트를 공유하거나 오류 결과를 반환해야 합니다.
처리기 메서드 M 는 문 AddHandler E, AddressOf M 도 유효한 경우 이벤트에 대한 유효한 이벤트 E 처리기로 간주됩니다.
AddHandler 그러나 문과 달리 명시적 이벤트 처리기는 strict 의미 체계가 사용되는지 여부에 관계없이 인수가 없는 메서드로 이벤트를 처리할 수 있습니다.
Option Strict On
Class C1
Event E(x As Integer)
End Class
Class C2
withEvents C1 As New C1()
' Valid
Sub M1() Handles C1.E
End Sub
Sub M2()
' Invalid
AddHandler C1.E, AddressOf M1
End Sub
End Class
단일 멤버는 여러 일치 이벤트를 처리할 수 있으며 여러 메서드는 단일 이벤트를 처리할 수 있습니다. 메서드의 접근성은 이벤트를 처리하는 기능에 영향을 주지 않습니다. 다음 예제에서는 메서드가 이벤트를 처리하는 방법을 보여 줍니다.
Class Raiser
Event E1()
Sub Raise()
RaiseEvent E1
End Sub
End Class
Module Test
WithEvents x As Raiser
Sub E1Handler() Handles x.E1
Console.WriteLine("Raised")
End Sub
Sub Main()
x = New Raiser()
x.Raise()
x.Raise()
End Sub
End Module
그러면 다음이 출력됩니다.
Raised
Raised
형식은 기본 형식에서 제공하는 모든 이벤트 처리기를 상속합니다. 파생 형식은 기본 형식에서 상속하는 이벤트 매핑을 어떤 방식으로든 변경할 수 없지만 이벤트에 추가 처리기를 추가할 수 있습니다.
확장 메서드
확장 메서드를 사용하여 형식 선언 외부에서 형식에 메서드를 추가할 수 있습니다. 확장 메서드는 특성이 적용된 System.Runtime.CompilerServices.ExtensionAttribute 메서드입니다. 표준 모듈에서만 선언할 수 있으며 메서드가 확장하는 형식을 지정하는 매개 변수가 하나 이상 있어야 합니다. 예를 들어 다음 확장 메서드는 형식 String을 확장합니다.
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension> _
Sub Print(s As String)
Console.WriteLine(s)
End Sub
End Module
메모. Visual Basic에서는 표준 모듈에서 확장 메서드를 선언해야 하지만 C#과 같은 다른 언어에서는 다른 형식으로 선언할 수 있습니다. 메서드가 여기에 설명된 다른 규칙을 따르고 포함된 형식이 열린 제네릭 형식이 아니고 인스턴스화할 수 없는 한 Visual Basic은 확장 메서드를 인식합니다.
확장 메서드가 호출되면 호출되는 인스턴스가 첫 번째 매개 변수에 전달됩니다. 첫 번째 매개 변수를 선언 Optional 하거나 ParamArray. 형식 매개 변수를 포함한 모든 형식은 확장 메서드의 첫 번째 매개 변수로 나타날 수 있습니다. 예를 들어 다음 메서드는 형식 Integer(), 구현하는 모든 형식 및 모든 형식을 확장합니다 System.Collections.Generic.IEnumerable(Of T).
Imports System.Runtime.CompilerServices
Module Extensions
<Extension> _
Sub PrintArray(a() As Integer)
...
End Sub
<Extension> _
Sub PrintList(Of T)(a As IEnumerable(Of T))
...
End Sub
<Extension> _
Sub Print(Of T)(a As T)
...
End Sub
End Module
이전 예제와 같이 인터페이스를 확장할 수 있습니다. 인터페이스 확장 메서드는 메서드의 구현을 제공하므로 확장 메서드가 정의된 인터페이스를 구현하는 형식은 인터페이스에서 원래 선언한 멤버만 구현합니다. 다음은 그 예입니다.
Imports System.Runtime.CompilerServices
Interface IAction
Sub DoAction()
End Interface
Module IActionExtensions
<Extension> _
Public Sub DoAnotherAction(i As IAction)
i.DoAction()
End Sub
End Module
Class C
Implements IAction
Sub DoAction() Implements IAction.DoAction
...
End Sub
' ERROR: Cannot implement extension method IAction.DoAnotherAction
Sub DoAnotherAction() Implements IAction.DoAnotherAction
...
End Sub
End Class
확장 메서드는 형식 매개 변수에 형식 제약 조건을 가질 수도 있으며 확장되지 않은 제네릭 메서드와 마찬가지로 형식 인수를 유추할 수 있습니다.
Imports System.Runtime.CompilerServices
Module IEnumerableComparableExtensions
<Extension> _
Public Function Sort(Of T As IComparable(Of T))(i As IEnumerable(Of T)) _
As IEnumerable(Of T)
...
End Function
End Module
확장되는 형식 내의 암시적 인스턴스 식을 통해 확장 메서드에 액세스할 수도 있습니다.
Imports System.Runtime.CompilerServices
Class C1
Sub M1()
Me.M2()
M2()
End Sub
End Class
Module C1Extensions
<Extension>
Sub M2(c As C1)
...
End Sub
End Module
접근성을 위해 확장 메서드는 선언된 표준 모듈의 멤버로 처리됩니다. 선언 컨텍스트를 통해 액세스 권한을 초과하여 확장 중인 형식의 멤버에 대한 추가 액세스 권한이 없습니다.
확장 메서드는 표준 모듈 메서드가 범위에 있는 경우에만 사용할 수 있습니다. 그렇지 않으면 원래 형식이 확장된 것으로 표시되지 않습니다. 다음은 그 예입니다.
Imports System.Runtime.CompilerServices
Class C1
End Class
Namespace N1
Module C1Extensions
<Extension> _
Sub M1(c As C1)
...
End Sub
End Module
End Namespace
Module Test
Sub Main()
Dim c As New C1()
' Error: c has no member named "M1"
c.M1()
End Sub
End Module
형식의 확장 메서드만 사용할 수 있는 경우 형식을 참조하면 컴파일 시간 오류가 계속 발생합니다.
확장 메서드는 강력한 For Each 형식 패턴과 같이 멤버가 바인딩된 모든 컨텍스트에서 형식의 멤버로 간주됩니다. 다음은 그 예입니다.
Imports System.Runtime.CompilerServices
Class C1
End Class
Class C1Enumerator
ReadOnly Property Current() As C1
Get
...
End Get
End Property
Function MoveNext() As Boolean
...
End Function
End Class
Module C1Extensions
<Extension> _
Function GetEnumerator(c As C1) As C1Enumerator
...
End Function
End Module
Module Test
Sub Main()
Dim c As New C1()
' Valid
For Each o As Object In c
...
Next o
End Sub
End Module
확장 메서드를 참조하는 대리자를 만들 수도 있습니다. 따라서 코드는 다음과 같습니다.
Delegate Sub D1()
Module Test
Sub Main()
Dim s As String = "Hello, World!"
Dim d As D1
d = AddressOf s.Print
d()
End Sub
End Module
은 다음과 거의 동일합니다.
Delegate Sub D1()
Module Test
Sub Main()
Dim s As String = "Hello, World!"
Dim d As D1
d = CType([Delegate].CreateDelegate(GetType(D1), s, _
GetType(StringExtensions).GetMethod("Print")), D1)
d()
End Sub
End Module
메모. Visual Basic은 일반적으로 메서드가 호출되는 인스턴스가 있는 경우 발생하는 인스턴스 메서드 호출 System.NullReferenceException 에 대한 Nothing검사를 삽입합니다. 확장 메서드의 경우 이 검사를 삽입하는 효율적인 방법이 없으므로 확장 메서드는 명시적으로 확인해야 Nothing합니다.
메모. 인터페이스로 형식화된 매개 변수에 인수로 ByVal 전달될 때 값 형식이 boxed됩니다. 이는 확장 메서드의 부작용이 원본이 아닌 구조의 복사본에서 작동한다는 것을 의미합니다. 언어는 확장 메서드의 첫 번째 인수에 제한을 두지 않지만 확장 메서드를 사용하여 값 형식을 확장하거나 값 형식을 확장할 때 첫 번째 매개 변수를 전달 ByRef 하여 부작용이 원래 값에서 작동하도록 하는 것이 좋습니다.
부분 메서드
partial 메서드는 시그니처를 지정하지만 메서드 본문은 지정하지 않는 메서드입니다. 메서드의 본문은 이름과 시그니처가 같은 다른 메서드 선언에서 제공할 수 있으며, 형식의 다른 부분 선언에서 제공될 가능성이 높습니다. 다음은 그 예입니다.
a.vb:
' Designer generated code
Public Partial Class MyForm
Private Partial Sub ValidateControls()
End Sub
Public Sub New()
' Initialize controls
...
ValidateControls()
End Sub
End Class
b.vb:
Public Partial Class MyForm
Public Sub ValidateControls()
' Validation logic goes here
...
End Sub
End Class
이 예제에서 클래스 MyForm 의 부분 선언은 구현이 없는 partial 메서드 ValidateControls 를 선언합니다. partial 선언의 생성자는 파일에 제공된 본문이 없더라도 partial 메서드를 호출합니다. 그런 다음 다른 MyForm 부분 선언은 메서드의 구현을 제공합니다.
부분 메서드는 본문이 제공되었는지 여부에 관계없이 호출할 수 있습니다. 메서드 본문이 제공되지 않으면 호출이 무시됩니다. 다음은 그 예입니다.
Public Class C1
Private Partial Sub M1()
End Sub
Public Sub New()
' Since no implementation is supplied, this call will not be made.
M1()
End Sub
End Class
무시되는 부분 메서드 호출에 인수로 전달되는 식도 무시되고 평가되지 않습니다. (참고. 즉, 부분 메서드는 사용되지 않는 경우 비용이 들지 않으므로 부분 메서드는 두 부분 형식에 정의된 동작을 제공하는 매우 효율적인 방법입니다.)
partial 메서드 선언은 본문에 문이 없는 서브루틴으로 Private 선언되어야 하며 항상 서브루틴이어야 합니다. 부분 메서드는 본문을 제공하는 메서드가 가능하지만 인터페이스 메서드를 직접 구현할 수 없습니다.
하나의 메서드만 부분 메서드에 본문을 제공할 수 있습니다. 부분 메서드에 본문을 제공하는 메서드는 partial 메서드와 동일한 서명, 모든 형식 매개 변수에 대한 동일한 제약 조건, 동일한 선언 한정자 및 동일한 매개 변수 및 형식 매개 변수 이름을 가져야 합니다. 부분 메서드의 특성과 해당 본문을 제공하는 메서드는 메서드의 매개 변수에 대한 특성과 마찬가지로 병합됩니다. 마찬가지로 메서드가 처리하는 이벤트 목록이 병합됩니다. 다음은 그 예입니다.
Class C1
Event E1()
Event E2()
Private Partial Sub S() Handles Me.E1
End Sub
' Handles both E1 and E2
Private Sub S() Handles Me.E2
...
End Sub
End Class
생성자
생성자는 초기화를 제어할 수 있는 특수 메서드입니다. 프로그램이 시작된 후 또는 형식의 인스턴스를 만든 후에 실행됩니다. 다른 멤버와 달리 생성자는 상속되지 않으며 형식의 선언 공간에 이름을 도입하지 않습니다. 생성자는 개체 생성 식 또는 .NET Framework에서만 호출할 수 있습니다. 직접 호출할 수 없습니다.
메모. 생성자는 서브루틴에 있는 줄 배치에 대해 동일한 제한을 가합니다. 시작 문, 끝 문 및 블록은 모두 논리 줄의 시작 부분에 나타나야 합니다.
ConstructorMemberDeclaration
: Attributes? ConstructorModifier* 'Sub' 'New'
( OpenParenthesis ParameterList? CloseParenthesis )? LineTerminator
Block?
'End' 'Sub' StatementTerminator
;
ConstructorModifier
: AccessModifier
| 'Shared'
;
인스턴스 생성자
인스턴스 생성자는 형식의 인스턴스를 초기화하고 인스턴스를 만들 때 .NET Framework에서 실행됩니다. 생성자의 매개 변수 목록에는 메서드의 매개 변수 목록과 동일한 규칙이 적용됩니다. 인스턴스 생성자가 오버로드될 수 있습니다.
참조 형식의 모든 생성자는 다른 생성자를 호출해야 합니다. 호출이 명시적이면 생성자 메서드 본문의 첫 번째 문이어야 합니다. 문은 형식의 다른 인스턴스 생성자(예 Me.New(...) : 또는 MyClass.New(...) 구조체가 아닌 경우)를 호출할 수 있습니다. 예를 들어 MyBase.New(...)형식의 기본 형식의 인스턴스 생성자를 호출할 수 있습니다. 생성자가 자신을 호출하는 것은 유효하지 않습니다. 생성자가 다른 생성 MyBase.New() 자에 대한 호출을 생략하면 암시적입니다. 매개 변수가 없는 기본 형식 생성자가 없으면 컴파일 시간 오류가 발생합니다.
Me 기본 클래스 생성자를 호출할 때까지 생성되는 것으로 간주되지 않으므로 생성자 호출 문에 대한 매개 변수는 암시적 또는 MyBase 명시적으로 참조MeMyClass할 수 없습니다.
생성자의 첫 번째 문이 폼 MyBase.New(...)인 경우 생성자는 형식에 선언된 인스턴스 변수의 변수 이니셜라이저로 지정된 초기화를 암시적으로 수행합니다. 이는 직접 기본 형식 생성자를 호출한 직후에 실행되는 할당 시퀀스에 해당합니다. 이러한 순서를 지정하면 인스턴스에 액세스할 수 있는 문이 실행되기 전에 모든 기본 인스턴스 변수가 변수 이니셜라이저에 의해 초기화됩니다. 다음은 그 예입니다.
Class A
Protected x As Integer = 1
End Class
Class B
Inherits A
Private y As Integer = x
Public Sub New()
Console.WriteLine("x = " & x & ", y = " & y)
End Sub
End Class
인스턴스B를 만드는 데 사용되는 경우 New B() 다음 출력이 생성됩니다.
x = 1, y = 1
값 y 은 1 기본 클래스 생성자가 호출된 후 변수 이니셜라이저가 실행되기 때문입니다. 변수 이니셜라이저는 형식 선언에 나타나는 텍스트 순서로 실행됩니다.
형식이 생성자만 Private 선언하는 경우 일반적으로 다른 형식이 형식에서 파생되거나 형식의 인스턴스를 만드는 것은 불가능합니다. 유일한 예외는 형식 내에 중첩된 형식입니다.
Private 생성자는 멤버만 Shared 포함하는 형식에서 일반적으로 사용됩니다.
형식에 인스턴스 생성자 선언이 없는 경우 기본 생성자가 자동으로 제공됩니다. 기본 생성자는 직접 기본 형식의 매개 변수가 없는 생성자를 호출합니다. 직접 기본 형식에 액세스 가능한 매개 변수가 없는 생성자가 없으면 컴파일 시간 오류가 발생합니다. 기본 생성자에 대해 선언된 액세스 형식은 형식이 아닌 경우이며 PublicMustInherit, 이 경우 기본 생성자는 .입니다 Protected.
메모. 형식의 기본 생성자에 대한 MustInherit 기본 액세스는 클래스를 직접 만들 수 없기 때문 MustInherit 입니다Protected. 따라서 기본 생성자를 Public만드는 데 아무런 의미가 없습니다.
다음 예제에서는 클래스에 생성자 선언이 없기 때문에 기본 생성자가 제공됩니다.
Class Message
Dim sender As Object
Dim text As String
End Class
따라서 이 예제는 다음과 정확히 동일합니다.
Class Message
Dim sender As Object
Dim text As String
Sub New()
End Sub
End Class
특성 Microsoft.VisualBasic.CompilerServices.DesignerGeneratedAttribute 으로 표시된 디자이너 생성 클래스로 내보내지는 기본 생성자는 기본 생성자를 호출한 후 메서드(있는 경우)를 호출 Sub InitializeComponent()합니다. (참고. 이렇게 하면 WinForms 디자이너에서 만든 파일과 같이 디자이너에서 생성된 파일을 디자이너 파일에서 생성자를 생략할 수 있습니다. 이렇게 하면 프로그래머가 직접 지정할 수 있습니다.)
공유 생성자
공유 생성자는 형식의 공유 변수를 초기화합니다. 프로그램이 실행을 시작한 후 형식의 멤버에 대한 참조 전에 실행됩니다. 공유 생성자는 표준 모듈에 없는 한 한정자를 지정 Shared 합니다. 이 경우 Shared 한정자가 암시됩니다.
인스턴스 생성자와 달리 공유 생성자는 암시적 공용 액세스 권한을 가지며 매개 변수가 없으며 다른 생성자를 호출할 수 없습니다. 공유 생성자의 첫 번째 문 앞에 공유 생성자는 형식에 선언된 공유 변수의 변수 이니셜라이저에 지정된 초기화를 암시적으로 수행합니다. 이는 생성자에 진입할 때 즉시 실행되는 일련의 할당에 해당합니다. 변수 이니셜라이저는 형식 선언에 나타나는 텍스트 순서로 실행됩니다.
다음 예제에서는 공유 변수를 Employee 초기화하는 공유 생성자가 있는 클래스를 보여 줍니다.
Imports System.Data
Class Employee
Private Shared ds As DataSet
Shared Sub New()
ds = New DataSet()
End Sub
Public Name As String
Public Salary As Decimal
End Class
닫힌 각 제네릭 형식에 대해 별도의 공유 생성자가 있습니다. 공유 생성자는 닫힌 각 형식에 대해 정확히 한 번 실행되므로 제약 조건을 통해 컴파일 시간에 확인할 수 없는 형식 매개 변수에 대해 런타임 검사를 적용하는 것이 편리합니다. 예를 들어 다음 형식은 공유 생성자를 사용하여 형식 매개 변수를 적용하거나 Double다음을 Integer 수행합니다.
Class EnumHolder(Of T)
Shared Sub New()
If Not GetType(T).IsEnum() Then
Throw New ArgumentException("T must be an enumerated type.")
End If
End Sub
End Class
공유 생성자가 실행되는 정확한 시기는 대부분 구현에 따라 달라지지만 공유 생성자가 명시적으로 정의된 경우 몇 가지 보장이 제공됩니다.
공유 생성자는 형식의 정적 필드에 대한 첫 번째 액세스 전에 실행됩니다.
공유 생성자는 형식의 정적 메서드를 처음 호출하기 전에 실행됩니다.
공유 생성자는 형식에 대한 생성자를 처음 호출하기 전에 실행됩니다.
위의 보장은 공유 이니셜라이저에 대해 공유 생성자가 암시적으로 만들어지는 상황에서는 적용되지 않습니다. 다음 예제의 출력은 로드의 정확한 순서 및 따라서 공유 생성자 실행이 정의되지 않았기 때문에 불확실합니다.
Module Test
Sub Main()
A.F()
B.F()
End Sub
End Module
Class A
Shared Sub New()
Console.WriteLine("Init A")
End Sub
Public Shared Sub F()
Console.WriteLine("A.F")
End Sub
End Class
Class B
Shared Sub New()
Console.WriteLine("Init B")
End Sub
Public Shared Sub F()
Console.WriteLine("B.F")
End Sub
End Class
출력은 다음 중 하나일 수 있습니다.
Init A
A.F
Init B
B.F
또는
Init B
Init A
A.F
B.F
반면, 다음 예제에서는 예측 가능한 출력을 생성합니다. 클래스가 Shared 파생되더라도 클래스 AB 의 생성자는 실행되지 않습니다.
Module Test
Sub Main()
B.G()
End Sub
End Module
Class A
Shared Sub New()
Console.WriteLine("Init A")
End Sub
End Class
Class B
Inherits A
Shared Sub New()
Console.WriteLine("Init B")
End Sub
Public Shared Sub G()
Console.WriteLine("B.G")
End Sub
End Class
결과는 다음과 같습니다.
Init B
B.G
다음 예제와 같이 변수 이니셜라이저가 있는 변수를 기본값 상태로 관찰할 수 있는 Shared 순환 종속성을 생성할 수도 있습니다.
Class A
Public Shared X As Integer = B.Y + 1
End Class
Class B
Public Shared Y As Integer = A.X + 1
Shared Sub Main()
Console.WriteLine("X = " & A.X & ", Y = " & B.Y)
End Sub
End Class
그러면 출력이 생성됩니다.
X = 1, Y = 2
메서드를 Main 실행하기 위해 시스템은 먼저 클래스 B를 로드합니다.
Shared 클래스 B 생성자는 초기 값을 Y계산합니다. 이 경우 값 A.X 이 참조되기 때문에 클래스 A 가 재귀적으로 로드됩니다.
Shared 클래스 A 의 생성자는 다시 진행하여 초기 값을 X계산하고, 이렇게 하면 기본값Y인 0을 가져옵니다.
A.X 가 .로 초기화됩니다 1. 그런 다음 로드 A 프로세스가 완료되고 초기 값의 Y계산으로 돌아가서 결과가 됩니다 2.
메서드가 Main 대신 클래스 A에 있으면 예제에서 다음 출력을 생성했을 것입니다.
X = 2, Y = 1
일반적으로 이러한 참조를 Shared 포함하는 클래스가 로드되는 순서를 확인할 수 없으므로 변수 이니셜라이저에서 순환 참조를 사용하지 않습니다.
이벤트
이벤트는 특정 발생의 코드를 알리는 데 사용됩니다. 이벤트 선언은 식별자, 대리자 형식 또는 매개 변수 목록 및 선택적 Implements 절로 구성됩니다.
EventMemberDeclaration
: RegularEventMemberDeclaration
| CustomEventMemberDeclaration
;
RegularEventMemberDeclaration
: Attributes? EventModifiers* 'Event'
Identifier ParametersOrType ImplementsClause? StatementTerminator
;
InterfaceEventMemberDeclaration
: Attributes? InterfaceEventModifiers* 'Event'
Identifier ParametersOrType StatementTerminator
;
ParametersOrType
: ( OpenParenthesis ParameterList? CloseParenthesis )?
| 'As' NonArrayTypeName
;
EventModifiers
: AccessModifier
| 'Shadows'
| 'Shared'
;
InterfaceEventModifiers
: 'Shadows'
;
대리자 형식을 지정하면 대리자 형식에 반환 형식이 없을 수 있습니다. 매개 변수 목록을 지정하면 매개 변수 또는 ParamArray 매개 변수가 포함되지 Optional 않을 수 있습니다. 매개 변수 형식 및/또는 대리자 형식의 접근성 도메인은 이벤트 자체의 접근성 도메인과 동일하거나 상위 집합이어야 합니다. 한정자를 지정하여 Shared 이벤트를 공유할 수 있습니다.
형식의 선언 공간에 추가된 멤버 이름 외에도 이벤트 선언은 다른 여러 멤버를 암시적으로 선언합니다. 이름이 지정된 X이벤트를 지정하면 다음 멤버가 선언 공간에 추가됩니다.
선언 형식이 메서드 선언인 경우 명명
XEventHandler된 중첩된 대리자 클래스가 도입됩니다. 중첩된 대리자 클래스는 메서드 선언과 일치하며 이벤트와 접근성이 동일합니다. 매개 변수 목록의 특성은 대리자 클래스의 매개 변수에 적용됩니다.Private대리XEvent자로 형식화된 인스턴스 변수입니다.명명
add_X된 두 메서드이며remove_X호출, 재정의 또는 오버로드할 수 없습니다.
형식이 위의 이름 중 하나와 일치하는 이름을 선언하려고 하면 컴파일 시간 오류가 발생하며 이름 바인딩을 위해 암시적 add_X 및 remove_X 선언이 무시됩니다. 파생 형식에서 섀도할 수 있지만 도입된 멤버를 재정의하거나 오버로드할 수는 없습니다. 예를 들어 클래스 선언
Class Raiser
Public Event Constructed(i As Integer)
End Class
는 다음 선언과 동일합니다.
Class Raiser
Public Delegate Sub ConstructedEventHandler(i As Integer)
Protected ConstructedEvent As ConstructedEventHandler
Public Sub add_Constructed(d As ConstructedEventHandler)
ConstructedEvent = _
CType( _
[Delegate].Combine(ConstructedEvent, d), _
Raiser.ConstructedEventHandler)
End Sub
Public Sub remove_Constructed(d As ConstructedEventHandler)
ConstructedEvent = _
CType( _
[Delegate].Remove(ConstructedEvent, d), _
Raiser.ConstructedEventHandler)
End Sub
End Class
대리자 형식을 지정하지 않고 이벤트를 선언하는 것이 가장 간단하고 간단한 구문이지만 각 이벤트에 대해 새 대리자 형식을 선언하는 단점이 있습니다. 예를 들어 다음 예제에서는 세 이벤트 모두 동일한 매개 변수 목록이 있더라도 숨겨진 대리자 형식 3개가 만들어집니다.
Public Class Button
Public Event Click(sender As Object, e As EventArgs)
Public Event DoubleClick(sender As Object, e As EventArgs)
Public Event RightClick(sender As Object, e As EventArgs)
End Class
다음 예제에서 이벤트는 단순히 동일한 대리 EventHandler자를 사용합니다.
Public Delegate Sub EventHandler(sender As Object, e As EventArgs)
Public Class Button
Public Event Click As EventHandler
Public Event DoubleClick As EventHandler
Public Event RightClick As EventHandler
End Class
이벤트는 정적 또는 동적으로 두 가지 방법 중 하나로 처리할 수 있습니다. 정적으로 이벤트를 처리하는 것은 더 간단하며 변수와 Handles 절만 필요합니다WithEvents. 다음 예제에서 클래스 Form1 는 개체Button의 이벤트를 Click 정적으로 처리합니다.
Public Class Form1
Public WithEvents Button1 As New Button()
Public Sub Button1_Click(sender As Object, e As EventArgs) _
Handles Button1.Click
Console.WriteLine("Button1 was clicked!")
End Sub
End Class
이벤트를 코드에서 명시적으로 연결하고 연결 해제해야 하므로 이벤트를 동적으로 처리하는 것이 더 복잡합니다. 이 문 AddHandler 은 이벤트에 대한 처리기를 추가하고 문 RemoveHandler 은 이벤트에 대한 처리기를 제거합니다. 다음 예제에서는 's 이벤트에 대한 Button1이벤트 처리기로 추가하는 Button1_Click 클래스 Form1 를 Click 보여줍니다.
Public Class Form1
Public Sub New()
' Add Button1_Click as an event handler for Button1's Click event.
AddHandler Button1.Click, AddressOf Button1_Click
End Sub
Private Button1 As Button = New Button()
Sub Button1_Click(sender As Object, e As EventArgs)
Console.WriteLine("Button1 was clicked!")
End Sub
Public Sub Disconnect()
RemoveHandler Button1.Click, AddressOf Button1_Click
End Sub
End Class
메서드 Disconnect에서 이벤트 처리기가 제거됩니다.
사용자 지정 이벤트
이전 섹션에서 설명한 것처럼 이벤트 선언은 이벤트 처리기를 추적하는 데 사용되는 필드, add_ 메서드 및 remove_ 메서드를 암시적으로 정의합니다. 그러나 경우에 따라 이벤트 처리기를 추적하기 위한 사용자 지정 코드를 제공하는 것이 바람직할 수 있습니다. 예를 들어 클래스가 소수만 처리할 40개의 이벤트를 정의하는 경우 40개 필드 대신 해시 테이블을 사용하여 각 이벤트에 대한 처리기를 추적하는 것이 더 효율적일 수 있습니다.
사용자 지정 이벤트를 사용하면 add_X 메서드와 remove_X 메서드를 명시적으로 정의할 수 있으므로 이벤트 처리기에 대한 사용자 지정 스토리지를 사용할 수 있습니다.
사용자 지정 이벤트는 키워드가 키워드 Custom 앞에 Event 와야 한다는 점을 제외하고 대리자 형식을 지정하는 이벤트가 선언되는 것과 동일한 방식으로 선언됩니다. 사용자 지정 이벤트 선언에는 선언, 선언 및 선언 AddHandler 의 세 가지 선언이 RemoveHandlerRaiseEvent 포함됩니다. 어떤 선언도 특성을 가질 수 있지만 어떤 한정자도 가질 수 없습니다.
CustomEventMemberDeclaration
: Attributes? EventModifiers* 'Custom' 'Event'
Identifier 'As' TypeName ImplementsClause? StatementTerminator
EventAccessorDeclaration+
'End' 'Event' StatementTerminator
;
EventAccessorDeclaration
: AddHandlerDeclaration
| RemoveHandlerDeclaration
| RaiseEventDeclaration
;
AddHandlerDeclaration
: Attributes? 'AddHandler'
OpenParenthesis ParameterList CloseParenthesis LineTerminator
Block?
'End' 'AddHandler' StatementTerminator
;
RemoveHandlerDeclaration
: Attributes? 'RemoveHandler'
OpenParenthesis ParameterList CloseParenthesis LineTerminator
Block?
'End' 'RemoveHandler' StatementTerminator
;
RaiseEventDeclaration
: Attributes? 'RaiseEvent'
OpenParenthesis ParameterList CloseParenthesis LineTerminator
Block?
'End' 'RaiseEvent' StatementTerminator
;
다음은 그 예입니다.
Class Test
Private Handlers As EventHandler
Public Custom Event TestEvent As EventHandler
AddHandler(value As EventHandler)
Handlers = CType([Delegate].Combine(Handlers, value), _
EventHandler)
End AddHandler
RemoveHandler(value as EventHandler)
Handlers = CType([Delegate].Remove(Handlers, value), _
EventHandler)
End RemoveHandler
RaiseEvent(sender As Object, e As EventArgs)
Dim TempHandlers As EventHandler = Handlers
If TempHandlers IsNot Nothing Then
TempHandlers(sender, e)
End If
End RaiseEvent
End Event
End Class
및 RemoveHandler 선언은 AddHandler 이벤트의 대리자 형식이어야 하는 하나의 ByVal 매개 변수를 취합니다.
AddHandler 또는 RemoveHandler 문이 실행되거나 Handles 절이 이벤트를 자동으로 처리하면 해당 선언이 호출됩니다. 선언은 RaiseEvent 이벤트 대리자와 동일한 매개 변수를 사용하며 문이 실행될 때 RaiseEvent 호출됩니다. 모든 선언을 제공해야 하며 하위 경로로 간주됩니다.
AddHandler
RemoveHandler
RaiseEvent 및 선언은 하위 경로에 있는 줄 배치에 대해 동일한 제한을 가합니다. 시작 문, 끝 문 및 블록은 모두 논리 줄의 시작 부분에 나타나야 합니다.
형식의 선언 공간에 추가된 멤버 이름 외에도 사용자 지정 이벤트 선언은 다른 여러 멤버를 암시적으로 선언합니다. 이름이 지정된 X이벤트를 지정하면 다음 멤버가 선언 공간에 추가됩니다.
선언에 해당하는 명명
add_X된 메서드입니다AddHandler.선언에 해당하는 명명
remove_X된 메서드입니다RemoveHandler.선언에 해당하는 명명
fire_X된 메서드입니다RaiseEvent.
형식이 위의 이름 중 하나와 일치하는 이름을 선언하려고 하면 컴파일 시간 오류가 발생하며 이름 바인딩을 위해 암시적 선언이 모두 무시됩니다. 파생 형식에서 섀도할 수 있지만 도입된 멤버를 재정의하거나 오버로드할 수는 없습니다.
메모.
Custom 은 예약된 단어가 아닙니다.
WinRT 어셈블리의 사용자 지정 이벤트
Microsoft Visual Basic 11.0을 기준으로 파일에서 선언되거나 /target:winmdobj이러한 파일의 인터페이스에서 선언된 후 다른 곳에서 구현된 이벤트는 약간 다르게 처리됩니다.
winmd를 빌드하는 데 사용되는 외부 도구는 일반적으로 특정 대리자 형식(예:
System.EventHandler(Of T)또는System.TypedEventHandle(Of T, U))만 허용하며 다른 대리자 형식은 허용하지 않습니다.필드에 대리
XEvent자 형식System.Runtime.InteropServices.WindowsRuntime.EventRegistrationTokenTable(Of T)이 있는T형식이 있습니다.AddHandler 접근자는 반환
System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken하고 RemoveHandler 접근자는 동일한 형식의 단일 매개 변수를 사용합니다.
이러한 사용자 지정 이벤트의 예는 다음과 같습니다.
Imports System.Runtime.InteropServices.WindowsRuntime
Public NotInheritable Class ClassInWinMD
Private XEvent As EventRegistrationTokenTable(Of EventHandler(Of Integer))
Public Custom Event X As EventHandler(Of Integer)
AddHandler(handler As EventHandler(Of Integer))
Return EventRegistrationTokenTable(Of EventHandler(Of Integer)).
GetOrCreateEventRegistrationTokenTable(XEvent).
AddEventHandler(handler)
End AddHandler
RemoveHandler(token As EventRegistrationToken)
EventRegistrationTokenTable(Of EventHandler(Of Integer)).
GetOrCreateEventRegistrationTokenTable(XEvent).
RemoveEventHandler(token)
End RemoveHandler
RaiseEvent(sender As Object, i As Integer)
Dim table = EventRegistrationTokenTable(Of EventHandler(Of Integer)).
GetOrCreateEventRegistrationTokenTable(XEvent).
InvocationList
If table IsNot Nothing Then table(sender, i)
End RaiseEvent
End Event
End Class
상수
상수는 형식의 멤버인 상수 값입니다.
ConstantMemberDeclaration
: Attributes? ConstantModifier* 'Const' ConstantDeclarators StatementTerminator
;
ConstantModifier
: AccessModifier
| 'Shadows'
;
ConstantDeclarators
: ConstantDeclarator ( Comma ConstantDeclarator )*
;
ConstantDeclarator
: Identifier ( 'As' TypeName )? Equals ConstantExpression StatementTerminator
;
상수는 암시적으로 공유됩니다. 선언에 절이 As 포함된 경우 절은 선언에 의해 도입된 멤버의 형식을 지정합니다. 형식을 생략하면 상수의 형식이 유추됩니다. 상수의 형식은 기본 형식 또는 Object. 상수가 형식으로 Object 지정되고 형식 문자가 없는 경우 상수의 실제 형식은 상수 식의 형식입니다. 그렇지 않은 경우 상수의 형식은 상수의 형식 문자 형식입니다.
다음 예제에서는 두 개의 공용 상수가 있는 클래스 Constants 를 보여 줍니다.
Class Constants
Public Const A As Integer = 1
Public Const B As Integer = A + 1
End Class
다음 예제와 같이 클래스를 통해 상수에 액세스할 수 있습니다. 이 예제에서는 값을 Constants.A 출력합니다 Constants.B.
Module Test
Sub Main()
Console.WriteLine(Constants.A & ", " & Constants.B)
End Sub
End Module
여러 상수 선언을 선언하는 상수 선언은 단일 상수의 여러 선언과 동일합니다. 다음 예제에서는 한 선언 문에 세 개의 상수 선언 합니다.
Class A
Protected Const x As Integer = 1, y As Long = 2, z As Short = 3
End Class
이 선언은 다음과 같습니다.
Class A
Protected Const x As Integer = 1
Protected Const y As Long = 2
Protected Const z As Short = 3
End Class
상수 형식의 접근성 도메인은 상수 자체의 접근성 도메인과 동일하거나 상위 집합이어야 합니다. 상수 식은 상수 형식 또는 상수의 형식으로 암시적으로 변환할 수 있는 형식의 값을 생성해야 합니다. 상수 식은 원형이 아닐 수 있습니다. 즉, 상수는 자체적인 측면에서 정의되지 않을 수 있습니다.
컴파일러는 상수 선언을 적절한 순서로 자동으로 평가합니다. 다음 예제에서 컴파일러는 먼저 10, 11 및 12 값을 각각 계산한 다음 Z마지막으로 X계산Y합니다.
Class A
Public Const X As Integer = B.Z + 1
Public Const Y As Integer = 10
End Class
Class B
Public Const Z As Integer = A.Y + 1
End Class
상수 값에 대한 기호화된 이름을 원하지만 값 형식이 상수 선언에서 허용되지 않거나 컴파일 시간에 상수 식으로 값을 계산할 수 없는 경우 읽기 전용 변수를 대신 사용할 수 있습니다.
인스턴스 및 공유 변수
인스턴스 또는 공유 변수는 정보를 저장할 수 있는 형식의 멤버입니다.
VariableMemberDeclaration
: Attributes? VariableModifier+ VariableDeclarators StatementTerminator
;
VariableModifier
: AccessModifier
| 'Shadows'
| 'Shared'
| 'ReadOnly'
| 'WithEvents'
| 'Dim'
;
VariableDeclarators
: VariableDeclarator ( Comma VariableDeclarator )*
;
VariableDeclarator
: VariableIdentifiers 'As' ObjectCreationExpression
| VariableIdentifiers ( 'As' TypeName )? ( Equals Expression )?
;
VariableIdentifiers
: VariableIdentifier ( Comma VariableIdentifier )*
;
VariableIdentifier
: Identifier IdentifierModifiers
;
Dim 한정자가 지정되지 않은 경우 한정자를 지정해야 하지만, 그렇지 않으면 생략할 수 있습니다. 단일 변수 선언에는 여러 변수 선언자가 포함될 수 있습니다. 각 변수 선언자는 새 인스턴스 또는 공유 멤버를 소개합니다.
이니셜라이저를 지정하면 변수 선언자가 인스턴스 또는 공유 변수를 하나만 선언할 수 있습니다.
Class Test
Dim a, b, c, d As Integer = 10 ' Invalid: multiple initialization
End Class
이 제한은 개체 이니셜라이저에는 적용되지 않습니다.
Class Test
Dim a, b, c, d As New Collection() ' OK
End Class
한정자를 사용하여 Shared 선언된 변수는 공유 변수입니다. 공유 변수는 생성된 형식의 인스턴스 수에 관계없이 정확히 하나의 스토리지 위치를 식별합니다. 공유 변수는 프로그램 실행을 시작하고 프로그램이 종료될 때 존재하지 않을 때 존재하게 됩니다.
공유 변수는 닫힌 특정 제네릭 형식의 인스턴스 간에만 공유됩니다. 예를 들어 프로그램은 다음과 같습니다.
Class C(Of V)
Shared InstanceCount As Integer = 0
Public Sub New()
InstanceCount += 1
End Sub
Public Shared ReadOnly Property Count() As Integer
Get
Return InstanceCount
End Get
End Property
End Class
Class Application
Shared Sub Main()
Dim x1 As New C(Of Integer)()
Console.WriteLine(C(Of Integer).Count)
Dim x2 As New C(Of Double)()
Console.WriteLine(C(Of Integer).Count)
Dim x3 As New C(Of Integer)()
Console.WriteLine(C(Of Integer).Count)
End Sub
End Class
출력:
1
1
2
한정자 없이 선언된 변수를 Shared인스턴스 변수라고 합니다. 클래스의 모든 인스턴스에는 클래스의 모든 인스턴스 변수에 대한 별도의 복사본이 포함됩니다. 참조 형식의 인스턴스 변수는 해당 형식의 새 인스턴스를 만들 때 존재하게 되며 해당 인스턴스 Finalize 에 대한 참조가 없고 메서드가 실행되면 존재하지 않습니다. 값 형식의 인스턴스 변수의 수명은 해당 변수가 속한 변수와 정확히 동일합니다. 즉, 값 형식의 변수가 존재하거나 존재하지 않는 경우 값 형식의 인스턴스 변수도 존재합니다.
선언자에 절이 As 포함된 경우 절은 선언에 의해 도입된 멤버의 형식을 지정합니다. 형식을 생략하고 엄격한 의미 체계를 사용하는 경우 컴파일 시간 오류가 발생합니다. 그렇지 않으면 멤버의 형식이 암시적으로 Object 또는 멤버 형식 문자의 형식입니다.
메모. 구문에는 모호성이 없습니다. 선언자가 형식을 생략하면 항상 다음 선언자의 형식을 사용합니다.
인스턴스 또는 공유 변수의 형식 또는 배열 요소 형식의 접근성 도메인은 인스턴스 또는 공유 변수 자체의 접근성 도메인과 동일하거나 상위 집합이어야 합니다.
다음 예제에서는 내부 인스턴스 변수가 있는 클래스를 보여 ColorredPartgreenPart줍니다.bluePart
Class Color
Friend redPart As Short
Friend bluePart As Short
Friend greenPart As Short
Public Sub New(red As Short, blue As Short, green As Short)
redPart = red
bluePart = blue
greenPart = green
End Sub
End Class
Read-Only 변수
인스턴스 또는 공유 변수 선언에 한정자가 포함된 ReadOnly 경우 선언에서 도입된 변수에 대한 할당은 선언의 일부 또는 동일한 클래스의 생성자에서만 발생할 수 있습니다. 특히 읽기 전용 인스턴스 또는 공유 변수에 대한 할당은 다음 상황에서만 허용됩니다.
선언에 변수 이니셜라이저를 포함하여 인스턴스 또는 공유 변수를 도입하는 변수 선언에서
인스턴스 변수의 경우 변수 선언을 포함하는 클래스의 인스턴스 생성자입니다. 인스턴스 변수는 정규화되지 않은 방식으로 또는 통해
Me서MyClass만 액세스할 수 있습니다.공유 변수의 경우 공유 변수 선언을 포함하는 클래스의 공유 생성자에서
공유 읽기 전용 변수는 상수 값에 대한 기호화된 이름을 원하는 경우와 상수 선언에서 값 형식이 허용되지 않거나 컴파일 시간에 상수 식으로 값을 계산할 수 없는 경우에 유용합니다.
이러한 첫 번째 애플리케이션의 예는 다른 프로그램에서 변경되지 않도록 색 공유 변수를 선언 ReadOnly 하는 예제입니다.
Class Color
Friend redPart As Short
Friend bluePart As Short
Friend greenPart As Short
Public Sub New(red As Short, blue As Short, green As Short)
redPart = red
bluePart = blue
greenPart = green
End Sub
Public Shared ReadOnly Red As Color = New Color(&HFF, 0, 0)
Public Shared ReadOnly Blue As Color = New Color(0, &HFF, 0)
Public Shared ReadOnly Green As Color = New Color(0, 0, &HFF)
Public Shared ReadOnly White As Color = New Color(&HFF, &HFF, &HFF)
End Class
상수 및 읽기 전용 공유 변수에는 서로 다른 의미 체계가 있습니다. 식에서 상수 값을 참조하는 경우 컴파일 시간에 상수 값을 가져오지만 식이 읽기 전용 공유 변수를 참조하는 경우 런타임까지 공유 변수의 값을 가져오지 않습니다. 두 개의 개별 프로그램으로 구성된 다음 애플리케이션을 고려합니다.
file1.vb:
Namespace Program1
Public Class Utils
Public Shared ReadOnly X As Integer = 1
End Class
End Namespace
file2.vb:
Namespace Program2
Module Test
Sub Main()
Console.WriteLine(Program1.Utils.X)
End Sub
End Module
End Namespace
네임스페이스는 Program1Program2 별도로 컴파일되는 두 프로그램을 나타냅니다. 변수 Program1.Utils.X 가 선언되므로 Shared ReadOnly명령문의 Console.WriteLine 값 출력은 컴파일 시간에 알려지지 않고 런타임에 가져옵니다. 따라서 값 X 이 변경되고 Program1 다시 컴파일되는 Console.WriteLine 경우 문은 다시 컴파일되지 않은 경우에도 Program2 새 값을 출력합니다. 그러나 상수였다면 X 해당 값 X 은 컴파일 당시에 얻었 Program2 을 것이며 다시 컴파일될 때까지 Program2 변경 내용의 Program1 영향을 받지 않았을 것입니다.
WithEvents 변수
형식은 한정자를 사용하여 이벤트를 발생시키는 인스턴스 또는 공유 변수를 선언하여 인스턴스 또는 공유 변수 중 하나에서 발생하는 일부 이벤트 WithEvents 집합을 처리한다고 선언할 수 있습니다. 다음은 그 예입니다.
Class Raiser
Public Event E1()
Public Sub Raise()
RaiseEvent E1
End Sub
End Class
Module Test
Private WithEvents x As Raiser
Private Sub E1Handler() Handles x.E1
Console.WriteLine("Raised")
End Sub
Public Sub Main()
x = New Raiser()
End Sub
End Module
이 예제에서 메서드 E1Handler 는 인스턴스 변수x에 저장된 형식 Raiser 의 인스턴스에 의해 발생하는 이벤트를 E1 처리합니다.
WithEvents 한정자를 사용하면 변수의 이름이 선행 밑줄로 바뀌고 이벤트 연결이 수행되는 동일한 이름의 속성으로 바뀝니다. 예를 들어 변수의 이름이 F면 이름이 바뀌 _F 고 속성 F 이 암시적으로 선언됩니다. 변수의 새 이름과 다른 선언 사이에 충돌이 있는 경우 컴파일 시간 오류가 보고됩니다. 변수에 적용된 모든 특성은 이름이 바뀐 변수로 이월됩니다.
선언에서 WithEvents 만든 암시적 속성은 관련 이벤트 처리기 후킹 및 해제를 처리합니다. 값이 변수에 할당되면 속성은 먼저 현재 변수에 있는 인스턴스의 이벤트에 대한 메서드를 호출 remove 합니다(있는 경우 기존 이벤트 처리기 해제). 다음으로 할당이 수행되고 속성은 변수의 새 인스턴스에서 이벤트에 대한 메서드를 호출 add 합니다(새 이벤트 처리기 연결). 다음 코드는 표준 모듈 Test의 위 코드와 동일합니다.
Module Test
Private _x As Raiser
Public Property x() As Raiser
Get
Return _x
End Get
Set (Value As Raiser)
' Unhook any existing handlers.
If _x IsNot Nothing Then
RemoveHandler _x.E1, AddressOf E1Handler
End If
' Change value.
_x = Value
' Hook-up new handlers.
If _x IsNot Nothing Then
AddHandler _x.E1, AddressOf E1Handler
End If
End Set
End Property
Sub E1Handler()
Console.WriteLine("Raised")
End Sub
Sub Main()
x = New Raiser()
End Sub
End Module
변수가 구조체로 형식화된 것처럼 WithEvents 인스턴스 또는 공유 변수를 선언하는 것은 유효하지 않습니다. 또한 WithEvents 구조체에 지정할 수 없으며 WithEventsReadOnly 결합할 수 없습니다.
변수 이니셜라이저
구조체의 클래스 및 인스턴스 변수 선언(공유 변수 선언은 아님)의 인스턴스 및 공유 변수 선언에는 변수 이니셜라이저가 포함될 수 있습니다. 변수의 경우 Shared 변수 이니셜라이저는 프로그램이 시작된 후 변수가 처음 참조되기 전에 실행되는 할당 문에 Shared 해당합니다. 인스턴스 변수의 경우 변수 이니셜라이저는 클래스의 인스턴스를 만들 때 실행되는 할당 문에 해당합니다. 매개 변수가 없는 생성자는 수정할 수 없으므로 구조체에 인스턴스 변수 이니셜라이저가 있을 수 없습니다.
다음 예제를 고려하세요.
Class Test
Public Shared x As Double = Math.Sqrt(2.0)
Public i As Integer = 100
Public s As String = "Hello"
End Class
Module TestModule
Sub Main()
Dim a As New Test()
Console.WriteLine("x = " & Test.x & ", i = " & a.i & ", s = " & a.s)
End Sub
End Module
이 예제에서는 다음 출력을 생성합니다.
x = 1.4142135623731, i = 100, s = Hello
클래스가 x 로드될 때 할당이 발생하고 클래스의 새 인스턴스가 is 만들어질 때 할당이 발생합니다.
변수 이니셜라이저를 형식 생성자 블록에 자동으로 삽입되는 할당 문으로 생각하면 유용합니다. 다음 예제에는 여러 인스턴스 변수 이니셜라이저가 포함되어 있습니다.
Class A
Private x As Integer = 1
Private y As Integer = -1
Private count As Integer
Public Sub New()
count = 0
End Sub
Public Sub New(n As Integer)
count = n
End Sub
End Class
Class B
Inherits A
Private sqrt2 As Double = Math.Sqrt(2.0)
Private items As ArrayList = New ArrayList(100)
Private max As Integer
Public Sub New()
Me.New(100)
items.Add("default")
End Sub
Public Sub New(n As Integer)
MyBase.New(n - 1)
max = n
End Sub
End Class
이 예제는 아래 표시된 코드에 해당하며, 각 주석은 자동으로 삽입된 문을 나타냅니다.
Class A
Private x, y, count As Integer
Public Sub New()
MyBase.New ' Invoke object() constructor.
x = 1 ' This is a variable initializer.
y = -1 ' This is a variable initializer.
count = 0
End Sub
Public Sub New(n As Integer)
MyBase.New ' Invoke object() constructor.
x = 1 ' This is a variable initializer.
y = - 1 ' This is a variable initializer.
count = n
End Sub
End Class
Class B
Inherits A
Private sqrt2 As Double
Private items As ArrayList
Private max As Integer
Public Sub New()
Me.New(100)
items.Add("default")
End Sub
Public Sub New(n As Integer)
MyBase.New(n - 1)
sqrt2 = Math.Sqrt(2.0) ' This is a variable initializer.
items = New ArrayList(100) ' This is a variable initializer.
max = n
End Sub
End Class
모든 변수는 변수 이니셜라이저가 실행되기 전에 해당 형식의 기본값으로 초기화됩니다. 다음은 그 예입니다.
Class Test
Public Shared b As Boolean
Public i As Integer
End Class
Module TestModule
Sub Main()
Dim t As New Test()
Console.WriteLine("b = " & Test.b & ", i = " & t.i)
End Sub
End Module
b 클래스가 로드될 때 자동으로 기본값으로 초기화되고 i 클래스의 인스턴스가 만들어질 때 자동으로 기본값으로 초기화되므로 앞의 코드는 다음 출력을 생성합니다.
b = False, i = 0
각 변수 이니셜라이저는 변수 형식 또는 변수의 형식으로 암시적으로 변환할 수 있는 형식의 값을 생성해야 합니다. 변수 이니셜라이저는 순환이거나 이니셜라이저 이후에 초기화될 변수를 참조할 수 있습니다. 이 경우 참조된 변수의 값은 이니셜라이저의 용도로 기본값입니다. 이러한 이니셜라이저는 모호한 값입니다.
변수 이니셜라이저에는 일반 이니셜라이저, 배열 크기 이니셜라이저 및 개체 이니셜라이저의 세 가지 형태가 있습니다. 처음 두 폼은 형식 이름 뒤에 있는 등호 뒤에 나타나고, 후자의 두 폼은 선언 자체의 일부입니다. 특정 선언에는 하나의 형식의 이니셜라이저만 사용할 수 있습니다.
일반 이니셜라이저
일반 이니셜라이저는 변수 형식으로 암시적으로 변환할 수 있는 식입니다. 형식 이름 뒤에 있는 등호 뒤에 나타나며 값으로 분류되어야 합니다. 다음은 그 예입니다.
Module Test
Dim x As Integer = 10
Dim y As Integer = 20
Sub Main()
Console.WriteLine("x = " & x & ", y = " & y)
End Sub
End Module
이 프로그램은 출력을 생성합니다.
x = 10, y = 20
변수 선언에 일반 이니셜라이저가 있는 경우 한 번에 하나의 변수만 선언할 수 있습니다. 다음은 그 예입니다.
Module Test
Sub Main()
' OK, only one variable declared at a time.
Dim x As Integer = 10, y As Integer = 20
' Error: Can't initialize multiple variables at once.
Dim a, b As Integer = 10
End Sub
End Module
개체 이니셜라이저
개체 이니셜라이저는 형식 이름 대신 개체 만들기 식을 사용하여 지정됩니다. 개체 이니셜라이저는 개체 생성 식의 결과를 변수에 할당하는 일반 이니셜라이저와 동일합니다. So
Module TestModule
Sub Main()
Dim x As New Test(10)
End Sub
End Module
동일하다
Module TestModule
Sub Main()
Dim x As Test = New Test(10)
End Sub
End Module
개체 이니셜라이저의 괄호는 항상 생성자에 대한 인수 목록으로 해석되며 배열 형식 한정자로 해석되지 않습니다. 개체 이니셜라이저가 있는 변수 이름에는 배열 형식 한정자 또는 nullable 형식 한정자가 있을 수 없습니다.
Array-Size 이니셜라이저
배열 크기 이니셜라이저는 식으로 표시된 차원 상한 집합을 제공하는 변수 이름의 한정자입니다.
ArraySizeInitializationModifier
: OpenParenthesis BoundList CloseParenthesis ArrayTypeModifiers?
;
BoundList
: Bound ( Comma Bound )*
;
Bound
: Expression
| '0' 'To' Expression
;
상한 식은 값으로 분류되어야 하며 암시적으로 변환할 Integer수 있어야 합니다. 상한 집합은 지정된 상한이 있는 배열 생성 식의 변수 이니셜라이저와 동일합니다. 배열 형식의 차원 수는 배열 크기 이니셜라이저에서 유추됩니다. So
Module Test
Sub Main()
Dim x(5, 10) As Integer
End Sub
End Module
동일하다
Module Test
Sub Main()
Dim x As Integer(,) = New Integer(5, 10) {}
End Sub
End Module
모든 상한은 -1보다 크거나 같아야 하며 모든 차원에는 상한이 지정되어 있어야 합니다. 초기화되는 배열의 요소 형식 자체가 배열 형식인 경우 배열 형식 한정자는 배열 크기 이니셜라이저의 오른쪽으로 이동합니다. 예를 들면 다음과 같습니다.
Module Test
Sub Main()
Dim x(5,10)(,,) As Integer
End Sub
End Module
는 형식이 3차원 배열의 2차원 배열인 지역 변수 x 를 선언합니다. 이 배열Integer은 첫 번째 차원과 0..10 두 번째 차원의 0..5 범위가 있는 배열로 초기화됩니다. 배열 크기 이니셜라이저를 사용하여 해당 형식이 배열 배열인 변수의 요소를 초기화할 수 없습니다.
배열 크기 이니셜라이저가 있는 변수 선언에는 해당 형식 또는 일반 이니셜라이저에 배열 형식 한정자가 있을 수 없습니다.
System.MarshalByRefObject 클래스
클래스에서 파생되는 클래스 System.MarshalByRefObject 는 복사(값 기준)가 아닌 프록시(즉, 참조)를 사용하여 컨텍스트 경계를 넘어 마샬링됩니다. 즉, 이러한 클래스의 인스턴스는 실제 인스턴스가 아니라 컨텍스트 경계를 넘어 변수 액세스 및 메서드 호출을 마샬링하는 스텁일 수 있습니다.
따라서 이러한 클래스에 정의된 변수의 스토리지 위치에 대한 참조를 만들 수 없습니다. 즉, 파생 클래스 System.MarshalByRefObject 로 형식화된 변수는 참조 매개 변수에 전달할 수 없으며 값 형식으로 형식화된 변수의 메서드와 변수에 액세스할 수 없습니다. 대신 Visual Basic은 이러한 클래스에 정의된 변수를 속성인 것처럼 처리합니다(속성에 대한 제한 사항이 동일하기 때문에).
이 규칙에는 한 가지 예외가 있습니다. 암시적 또는 명시적으로 정규화된 Me 멤버는 항상 프록시가 아닌 실제 개체로 보장되므로 위의 제한 Me 에서 제외됩니다.
속성
속성 은 변수의 자연스러운 확장입니다. 둘 다 연결된 형식의 명명된 멤버이며 변수 및 속성에 액세스하기 위한 구문은 동일합니다. 그러나 변수와 달리 속성은 스토리지 위치를 나타내지 않습니다. 대신 속성에는 값을 읽거나 쓰기 위해 실행할 문을 지정하는 접근자가 있습니다.
속성은 속성 선언으로 정의됩니다. 속성 선언의 첫 번째 부분은 필드 선언과 유사합니다. 두 번째 부분에는 접근자 Get 및/또는 접근자가 Set 포함됩니다.
PropertyMemberDeclaration
: RegularPropertyMemberDeclaration
| MustOverridePropertyMemberDeclaration
| AutoPropertyMemberDeclaration
;
PropertySignature
: 'Property'
Identifier ( OpenParenthesis ParameterList? CloseParenthesis )?
( 'As' Attributes? TypeName )?
;
RegularPropertyMemberDeclaration
: Attributes? PropertyModifier* PropertySignature
ImplementsClause? LineTerminator
PropertyAccessorDeclaration+
'End' 'Property' StatementTerminator
;
MustOverridePropertyMemberDeclaration
: Attributes? MustOverridePropertyModifier+ PropertySignature
ImplementsClause? StatementTerminator
;
AutoPropertyMemberDeclaration
: Attributes? AutoPropertyModifier* 'Property' Identifier
( OpenParenthesis ParameterList? CloseParenthesis )?
( 'As' Attributes? TypeName )? ( Equals Expression )?
ImplementsClause? LineTerminator
| Attributes? AutoPropertyModifier* 'Property' Identifier
( OpenParenthesis ParameterList? CloseParenthesis )?
'As' Attributes? 'New'
( NonArrayTypeName ( OpenParenthesis ArgumentList? CloseParenthesis )? )?
ObjectCreationExpressionInitializer?
ImplementsClause? LineTerminator
;
InterfacePropertyMemberDeclaration
: Attributes? InterfacePropertyModifier* PropertySignature StatementTerminator
;
AutoPropertyModifier
: AccessModifier
| 'Shadows'
| 'Shared'
| 'Overridable'
| 'NotOverridable'
| 'Overrides'
| 'Overloads'
;
PropertyModifier
: AutoPropertyModifier
| 'Default'
| 'ReadOnly'
| 'WriteOnly'
| 'Iterator'
;
MustOverridePropertyModifier
: PropertyModifier
| 'MustOverride'
;
InterfacePropertyModifier
: 'Shadows'
| 'Overloads'
| 'Default'
| 'ReadOnly'
| 'WriteOnly'
;
PropertyAccessorDeclaration
: PropertyGetDeclaration
| PropertySetDeclaration
;
아래 예제에서 클래스는 Button 속성을 정의합니다 Caption .
Public Class Button
Private captionValue As String
Public Property Caption() As String
Get
Return captionValue
End Get
Set (Value As String)
captionValue = value
Repaint()
End Set
End Property
...
End Class
위의 클래스에 Button 따라 다음 속성을 사용하는 Caption 예는 다음과 같습니다.
Dim okButton As Button = New Button()
okButton.Caption = "OK" ' Invokes Set accessor.
Dim s As String = okButton.Caption ' Invokes Get accessor.
Set 여기서 접근자가 속성에 값을 할당하여 호출되고 Get 식에서 속성을 참조하여 접근자가 호출됩니다.
속성에 대해 형식을 지정하지 않고 엄격한 의미 체계를 사용하는 경우 컴파일 시간 오류가 발생합니다. 그렇지 않으면 속성의 형식이 암시적으로 Object 또는 속성의 형식 문자 형식입니다. 속성 선언에는 속성 값을 검색하는 접근자, Set 속성 값을 저장하는 접근자 또는 둘 다 포함될 Get 수 있습니다. 속성이 메서드를 암시적으로 선언하므로 메서드와 동일한 한정자를 사용하여 속성을 선언할 수 있습니다. 속성이 인터페이스에 정의되거나 한정자를 사용하여 MustOverride 정의된 경우 속성 본문과 End 구문을 생략해야 합니다. 그렇지 않으면 컴파일 시간 오류가 발생합니다.
인덱스 매개 변수 목록은 속성의 서명을 구성하므로 속성은 인덱스 매개 변수에 오버로드될 수 있지만 속성 형식에서는 오버로드되지 않을 수 있습니다. 인덱스 매개 변수 목록은 일반 메서드와 동일합니다. 그러나 한정자를 사용하여 매개 변수를 수정 ByRef 할 수 없으며 해당 매개 변수의 이름은 Value 지정할 수 없습니다(접근자의 암시적 값 매개 변수용 Set 으로 예약됨).
속성은 다음과 같이 선언될 수 있습니다.
속성이 속성 형식 한정자를 지정하지 않으면 속성에 접근자와
Set접근자가 모두Get있어야 합니다. 이 속성은 읽기/쓰기 속성이라고 합니다.속성이 한정자를 지정
ReadOnly하는 경우 속성에는 접근자가 있어야Get하며 접근자가Set없을 수 있습니다. 이 속성은 읽기 전용 속성이라고 합니다. 읽기 전용 속성이 할당의 대상이 되는 것은 컴파일 시간 오류입니다.속성이 한정자를 지정
WriteOnly하는 경우 속성에는 접근자가 있어야Set하며 접근자가Get없을 수 있습니다. 이 속성은 쓰기 전용 속성이라고 합니다. 할당의 대상이나 메서드에 대한 인수를 제외하고 식에서 쓰기 전용 속성을 참조하는 것은 컴파일 시간 오류입니다.
Get 속성의 접근 Set 자와 접근자는 고유 멤버가 아니며 속성의 접근자를 별도로 선언할 수 없습니다. 다음 예제에서는 단일 읽기-쓰기 속성을 선언하지 않습니다. 대신 이름이 같은 두 개의 속성을 선언합니다. 하나는 읽기 전용이고 다른 하나는 쓰기 전용입니다.
Class A
Private nameValue As String
' Error, contains a duplicate member name.
Public ReadOnly Property Name() As String
Get
Return nameValue
End Get
End Property
' Error, contains a duplicate member name.
Public WriteOnly Property Name() As String
Set (Value As String)
nameValue = value
End Set
End Property
End Class
동일한 클래스에서 선언된 두 멤버의 이름은 같을 수 없으므로 컴파일 시간 오류가 발생합니다.
기본적으로 속성 및 접근자의 접근성은 속성 Get 자체의 접근성과 Set 동일합니다. 그러나 Get 접근자 및 접근자는 속성과 Set 별도로 접근성을 지정할 수도 있습니다. 이 경우 접근자의 접근성은 속성의 접근성보다 더 제한적이어야 하며 하나의 접근자만 속성과 다른 접근성 수준을 가질 수 있습니다. 액세스 형식은 다음과 같이 다소 제한적인 것으로 간주됩니다.
Private가 ,Protected FriendProtected또는Friend.보다Public더 제한적입니다.가 제한적입니다. 가 제한적입니다. Protected Friend가 .보다Public더 제한적입니다.
속성의 접근자 중 하나에 액세스할 수 있지만 다른 접근자가 액세스할 수 없는 경우 속성은 읽기 전용이거나 쓰기 전용인 것처럼 처리됩니다. 다음은 그 예입니다.
Class A
Public Property P() As Integer
Get
...
End Get
Private Set (Value As Integer)
...
End Set
End Property
End Class
Module Test
Sub Main()
Dim a As A = New A()
' Error: A.P is read-only in this context.
a.P = 10
End Sub
End Module
파생 형식이 속성을 숨기면 파생 속성은 읽기 및 쓰기와 관련하여 그림자 속성을 숨깁니다. 다음 예제에서 속성은 P 읽기 및 쓰기와 관련하여 속성을 A 숨깁니다P.B
Class A
Public WriteOnly Property P() As Integer
Set (Value As Integer)
End Set
End Property
End Class
Class B
Inherits A
Public Shadows ReadOnly Property P() As Integer
Get
End Get
End Property
End Class
Module Test
Sub Main()
Dim x As B = New B
B.P = 10 ' Error, B.P is read-only.
End Sub
End Module
반환 형식 또는 매개 변수 형식의 접근성 도메인은 속성 자체의 접근성 도메인과 동일하거나 상위 집합이어야 합니다. 속성에는 하나의 접근자와 하나의 SetGet 접근자만 있을 수 있습니다.
선언 및 호출 구문, , Overridable, OverridesMustOverrideNotOverridable및 MustInherit 속성의 차이점을 제외하고, 속성은 , NotOverridable, OverridesMustOverride및 메서드와 MustInherit 똑같이 Overridable동작합니다. 속성을 재정의하는 경우 재정의 속성은 동일한 형식(읽기-쓰기, 읽기 전용, 쓰기 전용)이어야 합니다. 속성에 Overridable 접근자를 Private 포함할 수 없습니다.
다음 예제 XOverridable 에서는 읽기 전용 속성이며 Overridable 읽기Y-쓰기 속성이며 Z 읽기-쓰기 속성입니다MustOverride.
MustInherit Class A
Private _y As Integer
Public Overridable ReadOnly Property X() As Integer
Get
Return 0
End Get
End Property
Public Overridable Property Y() As Integer
Get
Return _y
End Get
Set (Value As Integer)
_y = value
End Set
End Property
Public MustOverride Property Z() As Integer
End Class
MustOverride따라서 Z 포함하는 클래스 A 를 선언MustInherit해야 합니다.
반면 클래스에서 파생되는 클래스 A 는 다음과 같습니다.
Class B
Inherits A
Private _z As Integer
Public Overrides ReadOnly Property X() As Integer
Get
Return MyBase.X + 1
End Get
End Property
Public Overrides Property Y() As Integer
Get
Return MyBase.Y
End Get
Set (Value As Integer)
If value < 0 Then
MyBase.Y = 0
Else
MyBase.Y = Value
End If
End Set
End Property
Public Overrides Property Z() As Integer
Get
Return _z
End Get
Set (Value As Integer)
_z = Value
End Set
End Property
End Class
여기서 속성 X선언은 기본YZ 속성을 재정의합니다. 각 속성 선언은 해당 상속된 속성의 접근성 한정자, 형식 및 이름과 정확히 일치합니다.
Get 속성의 접근자 및 Set 속성 XY 접근자가 키워드를 MyBase 사용하여 상속된 속성에 액세스합니다. 속성 Z 선언은 속성을 재정 MustOverride 의하므로 클래스 BB 에는 미해결 MustOverride 멤버가 없으며 일반 클래스로 허용됩니다.
속성을 사용하여 리소스가 처음 참조될 때까지 리소스 초기화를 지연할 수 있습니다. 다음은 그 예입니다.
Imports System.IO
Public Class ConsoleStreams
Private Shared reader As TextReader
Private Shared writer As TextWriter
Private Shared errors As TextWriter
Public Shared ReadOnly Property [In]() As TextReader
Get
If reader Is Nothing Then
reader = Console.In
End If
Return reader
End Get
End Property
Public Shared ReadOnly Property Out() As TextWriter
Get
If writer Is Nothing Then
writer = Console.Out
End If
Return writer
End Get
End Property
Public Shared ReadOnly Property [Error]() As TextWriter
Get
If errors Is Nothing Then
errors = Console.Error
End If
Return errors
End Get
End Property
End Class
클래스에는 표준 입력, 출력 및 오류 디바이스를 나타내는 세 가지 속성인 ConsoleStreams, In, Out 및 Error이 포함됩니다. 이러한 멤버를 속성으로 노출하면 클래스가 ConsoleStreams 실제로 사용될 때까지 초기화를 지연할 수 있습니다. 예를 들어, 속성을 처음 참조할 Out 때와 ConsoleStreams.Out.WriteLine("hello, world")같이 출력 디바이스의 기본 TextWriter 이 초기화됩니다. 그러나 애플리케이션이 및 Error 속성을 참조 In 하지 않으면 해당 디바이스에 대해 개체가 만들어지지 않습니다.
접근자 선언 가져오기
속성 Get 선언을 Get 사용하여 접근자(getter)를 선언합니다. 속성 Get 선언은 키워드 Get 와 문 블록으로 구성됩니다. 속성이 지정된 PGet 경우 접근자 선언은 속성과 동일한 한정자, 형식 및 매개 변수 목록을 가진 이름의 get_P 메서드를 암시적으로 선언합니다. 형식에 해당 이름의 선언이 포함되어 있으면 컴파일 시간 오류가 발생하지만 이름 바인딩을 위해 암시적 선언은 무시됩니다.
속성과 이름이 같은 접근자 본문의 선언 공간에서 암시적으로 선언되는 Get 특수 지역 변수는 속성의 반환 값을 나타냅니다. 식에 사용되는 경우 지역 변수에는 특수 이름 확인 의미 체계가 있습니다. 호출 식과 같이 메서드 그룹으로 분류되는 식을 예상하는 컨텍스트에서 지역 변수를 사용하는 경우 이름은 지역 변수가 아닌 함수로 확인됩니다. 다음은 그 예입니다.
ReadOnly Property F(i As Integer) As Integer
Get
If i = 0 Then
F = 1 ' Sets the return value.
Else
F = F(i - 1) ' Recursive call.
End If
End Get
End Property
괄호를 사용하면 모호한 상황이 발생할 수 있습니다(예: F(1) 형식이 1차원 배열인 속성은 어디에 있는지 F ). 모든 모호한 상황에서 이름은 지역 변수가 아닌 속성으로 확인됩니다. 다음은 그 예입니다.
ReadOnly Property F(i As Integer) As Integer()
Get
If i = 0 Then
F = new Integer(2) { 1, 2, 3 }
Else
F = F(i - 1) ' Recursive call, not index.
End If
End Get
End Property
제어 흐름이 Get 접근자 본문을 벗어나면 지역 변수의 값이 호출 식으로 다시 전달됩니다. 접근자를 호출하는 Get 것은 개념적으로 변수 값을 읽는 것과 동일하기 때문에 다음 예제와 같이 접근자가 관찰 가능한 부작용을 갖는 것은 잘못된 프로그래밍 스타일로 Get 간주됩니다.
Class Counter
Private Value As Integer
Public ReadOnly Property NextValue() As Integer
Get
Value += 1
Return Value
End Get
End Property
End Class
속성 값 NextValue 은 이전에 속성에 액세스한 횟수에 따라 달라집니다. 따라서 속성에 액세스하면 관찰 가능한 부작용이 발생하며 대신 메서드로 속성을 구현해야 합니다.
접근자에 대한 "부작용 없음" 규칙이 변수에 Get 저장된 값을 반환하기 위해 접근자를 항상 작성해야 한다는 의미 Get 는 아닙니다.
Get 실제로 접근자는 여러 변수에 액세스하거나 메서드를 호출하여 속성 값을 계산하는 경우가 많습니다. 그러나 올바르게 디자인된 Get 접근자가 개체의 상태를 관찰할 수 있는 변경을 유발하는 작업을 수행하지 않습니다.
메모.
Get 접근자에는 서브루틴의 선 배치에 대한 제한이 동일합니다. 시작 문, 끝 문 및 블록은 모두 논리 줄의 시작 부분에 나타나야 합니다.
PropertyGetDeclaration
: Attributes? AccessModifier? 'Get' LineTerminator
Block?
'End' 'Get' StatementTerminator
;
접근자 선언 설정
Set 속성 집합 선언을 사용하여 접근자(setter)를 선언합니다. 속성 집합 선언은 키워드 Set, 선택적 매개 변수 목록 및 문 블록으로 구성됩니다. 명명 P된 속성을 지정하면 setter 선언은 속성과 동일한 한정자 및 매개 변수 목록을 가진 이름의 set_P 메서드를 암시적으로 선언합니다. 형식에 해당 이름의 선언이 포함되어 있으면 컴파일 시간 오류가 발생하지만 이름 바인딩을 위해 암시적 선언은 무시됩니다.
매개 변수 목록을 지정하는 경우 하나의 멤버가 있어야 하고, 해당 멤버에는 한 ByVal정자가 없어야 하며, 해당 형식은 속성 형식과 동일해야 합니다. 매개 변수는 설정되는 속성 값을 나타냅니다. 매개 변수를 생략하면 명명 Value 된 매개 변수가 암시적으로 선언됩니다.
메모.
Set 접근자에는 서브루틴의 선 배치에 대한 제한이 동일합니다. 시작 문, 끝 문 및 블록은 모두 논리 줄의 시작 부분에 나타나야 합니다.
PropertySetDeclaration
: Attributes? AccessModifier? 'Set'
( OpenParenthesis ParameterList? CloseParenthesis )? LineTerminator
Block?
'End' 'Set' StatementTerminator
;
기본 속성
한정자를 Default 지정하는 속성을 기본 속성이라고 부릅니다. 속성을 허용하는 모든 형식에는 인터페이스를 비롯한 기본 속성이 있을 수 있습니다. 속성 이름으로 인스턴스를 한정할 필요 없이 기본 속성을 참조할 수 있습니다. 따라서 클래스를 지정합니다.
Class Test
Public Default ReadOnly Property Item(i As Integer) As Integer
Get
Return i
End Get
End Property
End Class
코드
Module TestModule
Sub Main()
Dim x As Test = New Test()
Dim y As Integer
y = x(10)
End Sub
End Module
동일하다
Module TestModule
Sub Main()
Dim x As Test = New Test()
Dim y As Integer
y = x.Item(10)
End Sub
End Module
속성이 선언되면 Default상속 계층 구조에서 해당 이름에 오버로드된 모든 속성이 선언 Default 되었는지 여부에 관계없이 기본 속성이 됩니다. 기본 클래스가 다른 이름으로 기본 속성을 Default 선언할 때 파생 클래스에서 속성을 선언하는 경우 또는 같은 ShadowsOverrides다른 한정자가 필요하지 않습니다. 이는 기본 속성에 ID 또는 서명이 없으므로 숨기거나 오버로드할 수 없기 때문입니다. 다음은 그 예입니다.
Class Base
Public ReadOnly Default Property Item(i As Integer) As Integer
Get
Console.WriteLine("Base = " & i)
End Get
End Property
End Class
Class Derived
Inherits Base
' This hides Item, but does not change the default property.
Public Shadows ReadOnly Property Item(i As Integer) As Integer
Get
Console.WriteLine("Derived = " & i)
End Get
End Property
End Class
Class MoreDerived
Inherits Derived
' This declares a new default property, but not Item.
' This does not need to be declared Shadows
Public ReadOnly Default Property Value(i As Integer) As Integer
Get
Console.WriteLine("MoreDerived = " & i)
End Get
End Property
End Class
Module Test
Sub Main()
Dim x As MoreDerived = New MoreDerived()
Dim y As Integer
Dim z As Derived = x
y = x(10) ' Calls MoreDerived.Value.
y = x.Item(10) ' Calls Derived.Item
y = z(10) ' Calls Base.Item
End Sub
End Module
이 프로그램은 출력을 생성합니다.
MoreDerived = 10
Derived = 10
Base = 10
형식 내에서 선언된 모든 기본 속성은 이름이 같아야 하며 명확하게 한정자를 Default 지정해야 합니다. 인덱스 매개 변수가 없는 기본 속성은 포함하는 클래스의 인스턴스를 할당할 때 모호한 상황을 야기하므로 기본 속성에는 인덱스 매개 변수가 있어야 합니다. 또한 특정 이름에 오버로드된 속성 중 하나에 한정자가 포함된 Default 경우 해당 이름에 오버로드된 모든 속성이 이를 지정해야 합니다. 기본 속성이 아닐 Shared수 있으며 속성의 접근자 중 하나 이상이 되어서는 안 됩니다 Private.
자동으로 구현된 속성
속성이 접근자의 선언을 생략하면 속성이 인터페이스에 선언되거나 선언 MustOverride되지 않는 한 속성의 구현이 자동으로 제공됩니다. 인수가 없는 읽기/쓰기 속성만 자동으로 구현할 수 있습니다. 그렇지 않으면 컴파일 시간 오류가 발생합니다.
자동으로 구현된 속성은 다른 속성을 x재정의하는 속성이라도 속성과 동일한 형식의 프라이빗 지역 변수 _x 를 도입합니다. 지역 변수의 이름과 다른 선언 사이에 충돌이 있는 경우 컴파일 시간 오류가 보고됩니다. 자동으로 구현된 속성의 Get 접근자가 로컬의 값과 로컬 값을 설정하는 속성의 Set 접근자를 반환합니다. 예를 들어 선언은 다음과 같습니다.
Public Property x() As Integer
은 다음과 거의 동일합니다.
Private _x As Integer
Public Property x() As Integer
Get
Return _x
End Get
Set (value As Integer)
_x = value
End Set
End Property
변수 선언과 마찬가지로 자동으로 구현되는 속성에는 이니셜라이저가 포함될 수 있습니다. 다음은 그 예입니다.
Public Property x() As Integer = 10
Public Shared Property y() As New Customer() With { .Name = "Bob" }
메모. 자동으로 구현된 속성이 초기화되면 기본 필드가 아닌 속성을 통해 초기화됩니다. 이렇게 하면 재정의 속성이 필요한 경우 초기화를 가로챌 수 있습니다.
배열 이니셜라이저는 배열 범위를 명시적으로 지정할 방법이 없다는 점을 제외하고 자동으로 구현된 속성에서 허용됩니다. 다음은 그 예입니다.
' Valid
Property x As Integer() = {1, 2, 3}
Property y As Integer(,) = {{1, 2, 3}, {12, 13, 14}, {11, 10, 9}}
' Invalid
Property x4(5) As Short
반복기 속성
반복기 속성은 한정자가 있는 Iterator 속성입니다. 반복기 메서드(Section Iterator 메서드)가 사용되는 것과 동일한 이유로 사용됩니다. 이 메서드는 명령문에서 사용할 For Each 수 있는 시퀀스를 생성하는 편리한 방법으로 사용됩니다.
Get 반복기 속성의 접근자는 반복기 메서드와 동일한 방식으로 해석됩니다.
반복기 속성에는 명시적 Get 접근자가 있어야 하며 해당 형식은 IEnumerator또는 IEnumerable일부 IEnumerator(Of T)IEnumerable(Of T)T형식이어야 합니다.
반복기 속성의 예는 다음과 같습니다.
Class Family
Property Daughters As New List(Of String) From {"Beth", "Diane"}
Property Sons As New List(Of String) From {"Abe", "Carl"}
ReadOnly Iterator Property Children As IEnumerable(Of String)
Get
For Each name In Daughters : Yield name : Next
For Each name In Sons : Yield name : Next
End Get
End Property
End Class
Module Module1
Sub Main()
Dim x As New Family
For Each c In x.Children
Console.WriteLine(c) ' prints Beth, Diane, Abe, Carl
Next
End Sub
End Module
운영자
연산 자는 포함하는 클래스에 대한 기존 Visual Basic 연산자의 의미를 정의하는 메서드입니다. 연산자가 식의 클래스에 적용되면 연산자는 클래스에 정의된 연산자 메서드에 대한 호출로 컴파일됩니다. 클래스에 대한 연산자를 정의하는 것은 연산자를 오버로드하는 것으로도 알려져 있습니다.
OperatorDeclaration
: Attributes? OperatorModifier* 'Operator' OverloadableOperator
OpenParenthesis ParameterList CloseParenthesis
( 'As' Attributes? TypeName )? LineTerminator
Block?
'End' 'Operator' StatementTerminator
;
OperatorModifier
: 'Public' | 'Shared' | 'Overloads' | 'Shadows' | 'Widening' | 'Narrowing'
;
OverloadableOperator
: '+' | '-' | '*' | '/' | '\\' | '&' | 'Like' | 'Mod' | 'And' | 'Or' | 'Xor'
| '^' | '<' '<' | '>' '>' | '=' | '<' '>' | '>' | '<' | '>' '=' | '<' '='
| 'Not' | 'IsTrue' | 'IsFalse' | 'CType'
;
이미 존재하는 연산자를 오버로드할 수 없습니다. 실제로 이는 주로 변환 연산자에게 적용됩니다. 예를 들어 파생 클래스에서 기본 클래스로의 변환을 오버로드할 수 없습니다.
Class Base
End Class
Class Derived
' Cannot redefine conversion from Derived to Base,
' conversion will be ignored.
Public Shared Widening Operator CType(s As Derived) As Base
...
End Operator
End Class
연산자는 다음과 같은 단어의 일반적인 의미로 오버로드될 수도 있습니다.
Class Base
Public Shared Widening Operator CType(b As Base) As Integer
...
End Operator
Public Shared Narrowing Operator CType(i As Integer) As Base
...
End Operator
End Class
연산자 선언은 포함하는 형식의 선언 공간에 이름을 명시적으로 추가하지 않습니다. 그러나 "op_" 문자로 시작하는 해당 메서드를 암시적으로 선언합니다. 다음 섹션에서는 각 연산자의 해당 메서드 이름을 나열합니다.
정의할 수 있는 연산자의 세 가지 클래스는 단항 연산자, 이진 연산자 및 변환 연산자입니다. 모든 연산자 선언은 특정 제한을 공유합니다.
연산자 선언은 항상 다음과
Shared여야Public합니다.Public한정자가 가정되는 컨텍스트에서는 한정자를 생략할 수 있습니다.연산자의 매개 변수를 선언
ByRefOptionalParamArray할 수 없거나 .피연산자 또는 반환 값 중 하나 이상의 형식은 연산자를 포함하는 형식이어야 합니다.
연산자용으로 정의된 함수 반환 변수가 없습니다. 따라서 연산자
Return본문에서 값을 반환하려면 문을 사용해야 합니다.
이러한 제한에 대한 유일한 예외는 nullable 값 형식에 적용됩니다. nullable 값 형식에는 실제 형식 정의가 없으므로 값 형식은 nullable 버전의 형식에 대해 사용자 정의 연산자를 선언할 수 있습니다. 형식이 특정 사용자 정의 연산 ? 자를 선언할 수 있는지 여부를 결정할 때 유효성 검사를 위해 선언에 관련된 모든 형식에서 한정자가 먼저 삭제됩니다. 이 이완은 및 IsFalse 연산자의 반환 형식에는 IsTrue 적용되지 않습니다. 그렇지 않고 Boolean?여전히 반환Boolean해야 합니다.
연산자 선언에서는 연산자의 우선 순위와 결합성을 수정할 수 없습니다.
메모. 연산자는 서브루틴에 있는 줄 배치에 대해 동일한 제한을 가합니다. 시작 문, 끝 문 및 블록은 모두 논리 줄의 시작 부분에 나타나야 합니다.
단항 연산자
다음 단항 연산자를 오버로드할 수 있습니다.
단항 더하기 연산자
+(해당 메서드:op_UnaryPlus)단항 빼기 연산자
-(해당 메서드:op_UnaryNegation)논리
Not연산자(해당 메서드:op_OnesComplement)IsTrue및IsFalse연산자(해당 메서드:op_True,op_False)
오버로드된 모든 단항 연산자는 포함하는 형식의 단일 매개 변수를 가져와야 하며 반환해야 하는 형식을 IsFalse제외한 모든 형식을 IsTrue 반환Boolean할 수 있습니다. 포함하는 형식이 제네릭 형식인 경우 형식 매개 변수는 포함하는 형식의 형식 매개 변수와 일치해야 합니다. 예를 들면 다음과 같습니다.
Structure Complex
...
Public Shared Operator +(v As Complex) As Complex
Return v
End Operator
End Structure
형식이 중 하나 또는 IsFalse그 중 IsTrue 하나를 오버로드하는 경우 다른 형식도 오버로드해야 합니다. 오버로드가 하나만 있으면 컴파일 시간 오류가 발생합니다.
메모.
IsTrue 예약 IsFalse 된 단어가 아닙니다.
이진 연산자
다음 이진 연산자를 오버로드할 수 있습니다.
더하기
+, 빼기-, 곱하기, 나누기/*, 정수 분할\, 모듈로Mod및 지수 연산자^(해당 메서드:op_Addition, ,op_Multiplyop_Subtraction,op_IntegerDivisionop_Division,op_Modulus, )op_Exponent관계형 연산
=자,<>,<,>,>=<=(해당 메서드:op_Equality, ,op_LessThanop_Inequality,op_GreaterThan,op_LessThanOrEqualop_GreaterThanOrEqual)입니다. 메모. 같음 연산자를 오버로드할 수 있지만 대입 연산자(대입 문에만 사용됨)는 오버로드할 수 없습니다.연산자
Like(해당 메서드:op_Like)연결 연산자
&(해당 메서드:op_Concatenate)논리
AndOr및Xor연산자(해당 메서드:op_BitwiseAnd,op_BitwiseOr,op_ExclusiveOr)시프트 연산
<<자 및>>(해당 메서드:op_LeftShift,op_RightShift)
오버로드된 모든 이진 연산자는 포함하는 형식을 매개 변수 중 하나로 사용해야 합니다. 포함하는 형식이 제네릭 형식인 경우 형식 매개 변수는 포함하는 형식의 형식 매개 변수와 일치해야 합니다. 시프트 연산자는 첫 번째 매개 변수가 포함하는 형식이 되도록 이 규칙을 추가로 제한합니다. 두 번째 매개 변수는 항상 형식 Integer이어야 합니다.
다음 이진 연산자는 쌍으로 선언되어야 합니다.
연산자 및 연산자
=<>연산자 및 연산자
><연산자 및 연산자
>=<=
쌍 중 하나가 선언된 경우 다른 쌍도 일치하는 매개 변수 및 반환 형식으로 선언해야 합니다. 그렇지 않으면 컴파일 시간 오류가 발생합니다. (참고. 관계형 연산자의 쌍을 이루는 선언을 요구하는 목적은 오버로드된 연산자에서 최소 수준의 논리적 일관성을 시도하고 보장하는 것입니다.)
관계형 연산자와 달리 나누기 연산자와 정수 나누기 연산자를 오버로드하는 것은 오류가 아니지만 강력하게 권장되지 않습니다. (참고. 일반적으로 나누기의 두 가지 유형은 완전히 구별되어야 합니다. 나누기를 지원하는 형식은 정수(이 경우 지원 \해야 하는 경우)이거나 지원해야 하는 /형식이 아닙니다. 두 연산자를 모두 정의하는 것이 오류라고 생각했지만, 해당 언어가 일반적으로 Visual Basic과 같은 두 가지 유형의 나누기를 구분하지 않기 때문에 연습을 허용하는 것이 가장 안전하다고 생각했지만 강력하게 권장하지는 않습니다.)
복합 할당 연산자는 직접 오버로드할 수 없습니다. 대신 해당 이진 연산자가 오버로드되면 복합 할당 연산자는 오버로드된 연산자를 사용합니다. 다음은 그 예입니다.
Structure Complex
...
Public Shared Operator +(x As Complex, y As Complex) _
As Complex
...
End Operator
End Structure
Module Test
Sub Main()
Dim c1, c2 As Complex
' Calls the overloaded + operator
c1 += c2
End Sub
End Module
변환 연산자
변환 연산자는 형식 간의 새 변환을 정의합니다. 이러한 새 변환을 사용자 정의 변환이라고 합니다. 변환 연산자는 변환 연산자의 매개 변수 형식으로 표시된 원본 형식에서 변환 연산자의 반환 형식으로 표시된 대상 형식으로 변환합니다. 변환은 확대 또는 축소로 분류되어야 합니다. 키워드를 포함하는 Widening 변환 연산자 선언은 사용자 정의 확대 변환(해당 메서드: op_Implicit)을 도입합니다. 키워드를 포함하는 Narrowing 변환 연산자 선언은 사용자 정의 축소 변환(해당 메서드: op_Explicit)을 도입합니다.
일반적으로 사용자 정의 확대 변환은 예외를 throw하지 않고 정보를 잃지 않도록 설계해야 합니다. 사용자 정의 변환으로 인해 예외가 발생하거나(예: 원본 인수가 범위를 벗어났기 때문에) 정보 손실(예: 상위 비트 삭제)이 발생할 수 있는 경우 해당 변환은 축소 변환으로 정의되어야 합니다. 예제에서는 다음을 수행합니다.
Structure Digit
Dim value As Byte
Public Sub New(value As Byte)
if value < 0 OrElse value > 9 Then Throw New ArgumentException()
Me.value = value
End Sub
Public Shared Widening Operator CType(d As Digit) As Byte
Return d.value
End Operator
Public Shared Narrowing Operator CType(b As Byte) As Digit
Return New Digit(b)
End Operator
End Structure
Digit
Byte 변환은 예외를 throw하거나 정보를 잃지 않으므로 확대 변환이지만 DigitByte 변환은 축소 변환 Digit 이므로 가능한 값의 Byte하위 집합만 나타낼 수 있습니다.
오버로드할 수 있는 다른 모든 형식 멤버와 달리 변환 연산자의 서명에는 변환의 대상 형식이 포함됩니다. 반환 형식이 서명에 참여하는 유일한 형식 멤버입니다. 그러나 변환 연산자의 확대 또는 축소 분류는 연산자의 서명에 포함되지 않습니다. 따라서 클래스 또는 구조체는 확대 변환 연산자와 원본 및 대상 형식이 동일한 축소 변환 연산자를 둘 다 선언할 수 없습니다.
사용자 정의 변환 연산자는 포함하는 형식으로 또는 포함하는 형식에서 변환해야 합니다. 예를 들어 클래스 C 에서 변환을 정의할 IntegerIntegerCC 수 있습니다.IntegerBoolean 포함하는 형식이 제네릭 형식인 경우 형식 매개 변수는 포함하는 형식의 형식 매개 변수와 일치해야 합니다. 또한 내장(즉, 사용자 정의가 아닌) 변환을 다시 정의할 수 없습니다. 따라서 형식은 다음과 같은 변환을 선언할 수 없습니다.
원본 형식과 대상 형식은 동일합니다.
원본 형식과 대상 형식은 모두 변환 연산자를 정의하는 형식이 아닙니다.
원본 형식 또는 대상 형식이 인터페이스 형식입니다.
원본 형식 및 대상 형식은 상속(포함
Object)에 의해 관련됩니다.
이러한 규칙에 대한 유일한 예외는 nullable 값 형식에 적용됩니다. nullable 값 형식에는 실제 형식 정의가 없으므로 값 형식은 nullable 버전의 형식에 대해 사용자 정의 변환을 선언할 수 있습니다. 형식이 특정 사용자 정의 변환 ? 을 선언할 수 있는지 여부를 결정할 때 유효성 검사를 위해 선언에 관련된 모든 형식에서 한정자가 먼저 삭제됩니다. 따라서 변환을 정의할 수 있으므로 S 다음 선언이 S 유효합니다 T.
Structure T
...
End Structure
Structure S
Public Shared Widening Operator CType(ByVal v As S?) As T
...
End Operator
End Structure
그러나 구조체 S 에서 변환을 정의할 수 없으므로 다음 선언은 SS유효하지 않습니다.
Structure S
Public Shared Widening Operator CType(ByVal v As S) As S?
...
End Operator
End Structure
연산자 매핑
Visual Basic에서 지원하는 연산자 집합이 .NET Framework의 다른 언어에 있는 연산자 집합과 정확히 일치하지 않을 수 있으므로 일부 연산자는 정의되거나 사용될 때 다른 연산자로 특별히 매핑됩니다. 특히:
정수 나누기 연산자를 정의하면 정수 나누기 연산자를 호출하는 일반 나누기 연산자(다른 언어에서만 사용 가능)가 자동으로 정의됩니다.
,
And및 연산자를 오버로드Not하면 논리 연산자와Or비트 연산자를 구분하는 다른 언어의 관점에서 비트 연산자만 오버로드됩니다.논리 연산자와 비트 연산자를 구분하는 언어의 논리 연산자만 오버로드하는 클래스(예: 각각 , 및
op_LogicalOrforAndNotOr및 for를 사용하는op_LogicalNotop_LogicalAnd언어)는 해당 논리 연산자를 Visual Basic 논리 연산자로 매핑합니다. 논리 연산자와 비트 연산자가 모두 오버로드되면 비트 연산자만 사용됩니다.및
>>연산자를<<오버로드하면 서명된 시프트 연산자와 서명되지 않은 시프트 연산자를 구분하는 다른 언어의 관점에서 서명된 연산자만 오버로드됩니다.부호 없는 Shift 연산자만 오버로드하는 클래스는 서명되지 않은 Shift 연산자를 해당 Visual Basic Shift 연산자에 매핑합니다. 서명되지 않은 시프트 연산자와 부호 있는 Shift 연산자가 모두 오버로드되면 서명된 Shift 연산자만 사용됩니다.
Visual Basic language spec