Visual Basic의 식

식은 값의 계산을 지정하거나 변수 또는 상수로 지정하는 연산자와 피연산자의 시퀀스입니다. 이 장에서는 구문, 피연산자 및 연산자의 계산 순서 및 식의 의미를 정의합니다.

Expression
    : SimpleExpression
    | TypeExpression
    | MemberAccessExpression
    | DictionaryAccessExpression
    | InvocationExpression
    | IndexExpression
    | NewExpression
    | CastExpression
    | OperatorExpression
    | ConditionalExpression
    | LambdaExpression
    | QueryExpression
    | XMLLiteralExpression
    | XMLMemberAccessExpression
    ;

식 분류

모든 식은 다음 중 하나로 분류됩니다.

  • 값입니다. 모든 값에는 연결된 형식이 있습니다.

  • 변수입니다. 모든 변수에는 연결된 형식, 즉 선언된 변수 형식이 있습니다.

  • 네임스페이스입니다. 이 분류가 있는 식은 멤버 액세스의 왼쪽으로만 표시할 수 있습니다. 다른 컨텍스트에서는 네임스페이스로 분류된 식이 컴파일 시 오류를 발생시킵니다.

  • 형식 이 분류가 있는 식은 멤버 액세스의 왼쪽으로만 표시할 수 있습니다. 다른 상황에서 타입으로 분류된 식은 컴파일 오류를 발생시킵니다.

  • 동일한 이름에 오버로드된 메서드 집합인 메서드 그룹입니다. 메서드 그룹에는 연결된 대상 식과 연결된 형식 인수 목록이 있을 수 있습니다.

  • 메서드의 위치를 나타내는 메서드 포인터입니다. 메서드 포인터에는 연결된 대상 식과 연결된 형식 인수 목록이 있을 수 있습니다.

  • 무명 메서드인 람다 메서드입니다.

  • 동일한 이름에 오버로드된 속성 집합인 속성 그룹입니다. 속성 그룹에 연결된 대상 식이 있을 수 있습니다.

  • 속성 액세스입니다. 모든 속성 액세스에는 연결된 형식, 즉 속성의 형식이 있습니다. 속성 액세스에 연결된 대상 식이 있을 수 있습니다.

  • 런타임까지 지연된 메서드 또는 속성 액세스를 나타내는 런타임에 바인딩된 액세스입니다. 런타임에 바인딩된 액세스에는 연결된 대상 식과 연결된 형식 인수 목록이 있을 수 있습니다. 런타임에 바인딩된 액세스 유형은 항상 Object.입니다.

  • 이벤트 액세스입니다. 모든 이벤트 액세스에는 연결된 형식, 즉 이벤트 유형이 있습니다. 이벤트 액세스에 연결된 대상 식이 있을 수 있습니다. 이벤트 액세스는 , AddHandlerRemoveHandler 문의 첫 번째 인수RaiseEvent로 나타날 수 있습니다. 다른 모든 컨텍스트에서 이벤트 액세스로 분류된 표현은 컴파일 시간 오류를 유발합니다.

  • 형식이 아직 결정되지 않은 배열의 초기 값을 나타내는 배열 리터럴입니다.

  • 비우다. 식이 서브루틴의 호출이거나 결과가 없는 await 연산자 식일 때 발생합니다. void로 분류된 식은 호출 문 또는 await 문의 컨텍스트에서만 유효합니다.

  • 기본값입니다. 리터럴 Nothing 만 이 분류를 생성합니다.

식의 최종 결과는 일반적으로 값 또는 변수이며, 식의 다른 범주는 특정 컨텍스트에서만 허용되는 중간 값으로 작동합니다.

형식 매개 변수에 적용된 제약 조건이 해당 특성을 충족하는 경우 식 형식이 특정 특성(예: 참조 형식, 값 형식, 일부 형식에서 파생되는 등)을 포함해야 하는 문 및 식에서 형식 매개 변수인 식을 사용할 수 있습니다.

식 재분류

일반적으로 식과 다른 분류가 필요한 컨텍스트에서 식을 사용하는 경우 컴파일 시간 오류가 발생합니다(예: 리터럴에 값을 할당하려고 시도). 그러나 대부분의 경우 재분류 프로세스를 통해 식의 분류를 변경할 수 있습니다.

재분류에 성공하면 재분류가 확대 또는 축소로 판단됩니다. 달리 명시되지 않는 한, 이 목록의 모든 재분류가 확대되고 있습니다.

다음 형식의 식을 다시 분류할 수 있습니다.

  • 변수를 값으로 다시 분류할 수 있습니다. 변수에 저장된 값이 페치됩니다.

  • 메서드 그룹을 값으로 다시 분류할 수 있습니다. 메서드 그룹 식은 연결된 대상 식 및 형식 매개 변수 목록과 빈 괄호(즉, f 해석되고 해석됨)가 있는 호출 식으로 f()f(Of Integer)f(Of Integer)()해석됩니다. 이 재분류로 인해 식이 void로 더 재분류될 수 있습니다.

  • 메서드 포인터를 값으로 다시 분류할 수 있습니다. 이 재분류는 대상 형식이 알려진 변환의 컨텍스트에서만 발생할 수 있습니다. 메서드 포인터 식은 연결된 형식 인수 목록을 사용하여 적절한 형식의 대리자 인스턴스화 식에 대한 인수로 해석됩니다. 다음은 그 예입니다.

    Delegate Sub D(i As Integer)
    
    Module Test
        Sub F(i As Integer)
        End Sub
    
        Sub Main()
            Dim del As D
    
            ' The next two lines are equivalent.
            del = AddressOf F
            del = New D(AddressOf F)
        End Sub
    End Module
    
  • 람다 메서드는 값으로 다시 분류할 수 있습니다. 대상 형식이 알려진 변환 컨텍스트에서 재분류가 발생하는 경우 두 재분류 중 하나가 발생할 수 있습니다.

    1. 대상 형식이 대리자 형식인 경우 람다 메서드는 적절한 형식의 대리자 생성 식에 대한 인수로 해석됩니다.

    2. 대상 형식이 System.Linq.Expressions.Expression(Of T)대리자 형식이고 T 대리자 형식인 경우 람다 메서드는 대리자 생성 식 T 에서 사용되는 것처럼 해석된 다음 식 트리로 변환됩니다.

    비동기 또는 반복기 람다 메서드는 대리자에 ByRef 매개 변수가 없는 경우에만 대리자 생성 식에 대한 인수로 해석될 수 있습니다.

    대리자의 매개 변수 형식에서 해당 람다 매개 변수 형식으로의 변환이 축소 변환인 경우 재분류는 축소로 판단됩니다. 그렇지 않으면 확대됩니다.

    메모. 람다 메서드와 식 트리 간의 정확한 변환은 컴파일러 버전 간에 수정되지 않을 수 있으며 이 사양의 범위를 벗어버릅니다. Microsoft Visual Basic 11.0의 경우 모든 람다 식은 다음 제한 사항에 따라 식 트리로 변환될 수 있습니다. (1) 1. ByRef 매개 변수가 없는 한 줄 람다 식만 식 트리로 변환할 수 있습니다. 한 줄 Sub 람다 중에서 호출 문만 식 트리로 변환할 수 있습니다. (2) 이전 필드 이니셜라이저를 사용하여 후속 필드 이니셜라이저를 초기화하는 경우 익명 형식 식을 식 트리로 변환할 수 없습니다. New With {.a=1, .b=.a} (3) 초기화 중인 현재 개체의 멤버가 필드 이니셜라이저 중 하나에서 사용되는 경우 개체 이니셜라이저 식을 식 트리로 변환할 수 없습니다. New C1 With {.a=1, .b=.Method1()} (4) 다차원 배열 생성 식은 요소 형식을 명시적으로 선언하는 경우에만 식 트리로 변환할 수 있습니다. (5) 런타임 바인딩 식은 식 트리로 변환할 수 없습니다. (6) 변수 또는 필드가 호출 식에 ByRef를 전달하지만 ByRef 매개 변수와 형식이 정확히 같지 않거나 속성이 ByRef로 전달될 때 일반 VB 의미 체계는 인수의 복사본이 ByRef로 전달되고 최종 값이 변수 또는 필드 또는 속성으로 다시 복사되는 것입니다. 식 트리에서는 복사가 수행되지 않습니다. (7) 이러한 모든 제한은 중첩된 람다 식에도 적용됩니다.

    대상 형식을 알 수 없는 경우 람다 메서드는 람다 메서드의 시그니처가 동일한 익명 대리자 형식의 대리자 인스턴스화 식에 대한 인수로 해석됩니다. 엄격한 의미 체계를 사용하고 매개 변수의 형식을 생략하면 컴파일 시간 오류가 발생합니다. 그렇지 않으면 Object 누락된 매개 변수 형식으로 대체됩니다. 다음은 그 예입니다.

    Module Test
        Sub Main()
            ' Type of x will be equivalent to Func(Of Object, Object, Object)
            Dim x = Function(a, b) a + b
    
            ' Type of y will be equivalent to Action(Of Object, Object)
            Dim y = Sub(a, b) Console.WriteLine(a + b)
        End Sub
    End Module
    
  • 속성 그룹을 속성 액세스 권한으로 다시 분류할 수 있습니다. 속성 그룹 식은 빈 괄호(즉, f 해석됨)가 있는 인덱스 식으로 f()해석됩니다.

  • 속성 액세스를 값으로 다시 분류할 수 있습니다. 속성 액세스 식은 속성 접근자의 Get 호출 식으로 해석됩니다. 속성에 getter가 없으면 컴파일 시간 오류가 발생합니다.

  • 런타임에 바인딩된 액세스는 런타임에 바인딩된 메서드 또는 런타임에 바인딩된 속성 액세스로 다시 분류할 수 있습니다. 런타임에 바인딩된 액세스를 메서드 액세스 및 속성 액세스로 다시 분류할 수 있는 경우 속성 액세스로 재분류하는 것이 좋습니다.

  • 런타임에 바인딩된 액세스를 값으로 다시 분류할 수 있습니다.

  • 배열 리터럴을 값으로 다시 분류할 수 있습니다. 값의 형식은 다음과 같이 결정됩니다.

    1. 대상 형식이 알려져 있고 대상 형식이 배열 형식인 변환 컨텍스트에서 재분류가 발생하면 배열 리터럴이 T() 형식의 값으로 다시 분류됩니다. 대상 형식이 System.Collections.Generic.IList(Of T), IReadOnlyList(Of T), , IReadOnlyCollection(Of T)ICollection(Of T)또는 IEnumerable(Of T)배열 리터럴에 한 수준의 중첩이 있는 경우 배열 리터럴은 형식T()의 값으로 다시 분류됩니다.

    2. 그렇지 않으면 배열 리터럴은 이니셜라이저에 있는 요소의 주요 형식에 의해 결정되는 요소 형식을 사용하여 중첩 수준과 동일한 순위 배열인 값으로 재분류됩니다. 주요 형식을 확인할 Object 수 없으면 사용됩니다. 다음은 그 예입니다.

      ' x Is GetType(Double(,,))
      Dim x = { { { 1, 2.0 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } }.GetType()
      
      ' y Is GetType(Integer())
      Dim y = { 1, 2, 3 }.GetType()
      
      ' z Is GetType(Object())
      Dim z = { 1, "2" }.GetType()
      
      ' Error: Inconsistent nesting
      Dim a = { { 10 }, { 20, 30 } }.GetType()
      

    메모. 언어 버전 9.0과 버전 10.0 사이에 약간의 동작이 변경되었습니다. 10.0 이전에는 배열 요소 이니셜라이저가 지역 변수 형식 유추에 영향을 미치지 않았으며 이제는 그렇게 합니다. 따라서 Dim a() = { 1, 2, 3 } 언어 버전 a 9.0 및 Integer() 버전 10.0의 형식으로 유추 Object() 했을 것입니다.

    그런 다음 재분류는 배열 리터럴을 배열 생성 식으로 다시 해석합니다. 따라서 예제는 다음과 같습니다.

    Dim x As Double = { 1, 2, 3, 4 }
    Dim y = { "a", "b" }
    

    은 다음과 같습니다.

    Dim x As Double = New Double() { 1, 2, 3, 4 }
    Dim y = New String() { "a", "b" }
    

    재분류는 요소 식에서 배열 요소 형식으로의 변환이 축소되는 경우 축소로 판단됩니다. 그렇지 않으면 확대로 판단됩니다.

  • 기본값은 값 Nothing 으로 다시 분류할 수 있습니다. 대상 형식이 알려진 컨텍스트에서 결과는 대상 형식의 기본값입니다. 대상 형식을 알 수 없는 컨텍스트에서 결과는 형식 Object의 null 값입니다.

네임스페이스 식, 형식 식, 이벤트 액세스 식 또는 void 식을 다시 분류할 수 없습니다. 동시에 여러 재분류를 수행할 수 있습니다. 다음은 그 예입니다.

Module Test
    Sub F(i As Integer)
    End Sub

    ReadOnly Property P() As Integer
        Get
        End Get
    End Sub

    Sub Main()
        F(P)
    End Property
End Module

이 경우 속성 그룹 식 P 은 먼저 속성 그룹에서 속성 액세스로 다시 분류된 다음 속성 액세스에서 값으로 다시 분류됩니다. 컨텍스트에서 유효한 분류에 도달하기 위해 가장 적은 수의 재분류가 수행됩니다.

상수 식

상수 식은 컴파일 시간에 값을 완전히 평가할 수 있는 식입니다.

ConstantExpression
    : Expression
    ;

상수 식의 형식은 , ,SByte, UShort, Short, UInteger, IntegerULong, LongSingleChar, Double, DateDecimal, BooleanObjectString, 또는 열거형 형식일 Byte수 있습니다. 다음 구문은 상수 식에서 허용됩니다.

  • 리터럴(포함 Nothing)

  • 상수 형식 멤버 또는 상수 로컬에 대한 참조입니다.

  • 열거형 형식의 멤버에 대한 참조입니다.

  • 괄호가 있는 하위 식입니다.

  • 대상 형식이 위에 나열된 형식 중 하나인 경우 강제 변환 식입니다. String 변환은 항상 런타임에 실행 환경의 현재 문화권에서 수행되므로 이 규칙에 대한 강제 변환은 이 규칙의 예외이며 null 값 String 에서만 허용됩니다. 상수 강제 변환 식은 내장 변환만 사용할 수 있습니다.

  • +피연산자와 Not 결과가 위에 나열된 형식인 경우 단 - 항 연산자입니다.

  • +각 피연산자 및 결과가 위에 나열된 형식의 경우 , AndAlsoOrElseOrAnd-/\Mod<<^>><Xor&*><>=, <==> 이진 연산자입니다.

  • 조건부 연산자 If는 위에 나열된 형식의 각 피연산자와 결과를 제공합니다.

  • 다음 런타임 함수는 Microsoft.VisualBasic.Strings.ChrWMicrosoft.VisualBasic.Strings.Chr 상수 값이 0에서 128 Microsoft.VisualBasic.Strings.AscW 사이인 경우, 상수 문자열이 비어 Microsoft.VisualBasic.Strings.Asc 있지 않은 경우, 상수 문자열이 비어 있지 않은 경우입니다.

다음 구문은 상수 식에서 허용되지 않습니다 .

  • 컨텍스트를 With 통한 암시적 바인딩

정수 계열 형식의 상수 식(ULong, , Long, UInteger, Integer, ShortSByteUShort또는Byte)은 암시적으로 더 좁은 정수 형식으로 변환될 수 있으며, 상수 식의 값이 대상 형식 범위 내에 있는 경우 형식 Double 의 상수 식은 암시적으로 변환Single될 수 있습니다. 이러한 축소 변환은 허용 또는 엄격한 의미 체계가 사용되는지 여부에 관계없이 허용됩니다.

Late-Bound 식

멤버 액세스 식 또는 인덱스 식의 대상이 형식 Object이면 런타임까지 식 처리가 지연될 수 있습니다. 이러한 방식으로 처리를 지연하는 것을 런타임에 바인딩이라고 합니다. 런타임 바인딩을 Object 사용하면 변수를 형식 없는 방식으로 사용할 수 있습니다. 여기서 멤버의 모든 해상도는 변수에 있는 값의 실제 런타임 형식을 기반으로 합니다. 컴파일 환경이나 Option Strict컴파일 환경에서 엄격한 의미 체계를 지정하면 런타임 바인딩으로 인해 컴파일 시간 오류가 발생합니다. 오버로드 확인의 목적을 포함하여 런타임에 바인딩을 수행하는 경우 공용이 아닌 멤버는 무시됩니다. 초기 바인딩된 경우와 달리 멤버 런타임에 호출 대상을 Shared 호출하거나 액세스하면 호출 대상이 런타임에 평가됩니다. 식이 정의된 멤버에 대한 호출 식이면 런타임에 System.Object바인딩이 수행되지 않습니다.

일반적으로 런타임에 바인딩된 액세스는 식의 실제 런타임 형식에 대한 식별자를 조회하여 확인됩니다. 런타임에 런타임에 런타임에 런타임에 바인딩된 멤버 조회가 실패하면 예외가 System.MissingMemberException throw됩니다. 런타임에 바인딩된 멤버 조회는 연결된 대상 식의 런타임 형식에서만 수행되므로 개체의 런타임 형식은 인터페이스가 되지 않습니다. 따라서 런타임에 바인딩된 멤버 액세스 식에서 인터페이스 멤버에 액세스하는 것은 불가능합니다.

런타임에 바인딩된 멤버 액세스에 대한 인수는 매개 변수가 런타임에 바인딩된 멤버에 선언되는 순서가 아니라 멤버 액세스 식에 표시되는 순서대로 평가됩니다. 다음 예제에서는 이러한 차이점을 보여 줍니다.

Class C
    Public Sub f(ByVal x As Integer, ByVal y As Integer)
    End Sub
End Class

Module Module1
    Sub Main()
        Console.Write("Early-bound: ")
        Dim c As C = New C
        c.f(y:=t("y"), x:=t("x"))

        Console.Write(vbCrLf & "Late-bound: ")
        Dim o As Object = New C
        o.f(y:=t("y"), x:=t("x"))
    End Sub

    Function t(ByVal s As String) As Integer
        Console.Write(s)
        Return 0
    End Function
End Module

이 코드는 다음을 표시합니다.

Early-bound: xy
Late-bound: yx

런타임 인수 형식에서 런타임 오버로드 확인이 수행되므로 식이 컴파일 시간 또는 런타임에 평가되는지 여부에 따라 다른 결과를 생성할 수 있습니다. 다음 예제에서는 이러한 차이점을 보여 줍니다.

Class Base
End Class

Class Derived
    Inherits Base
End Class

Module Test
    Sub F(b As Base)
        Console.WriteLine("F(Base)")
    End Sub

    Sub F(d As Derived)
        Console.WriteLine("F(Derived)")
    End Sub

    Sub Main()
        Dim b As Base = New Derived()
        Dim o As Object = b

        F(b)
        F(o)
    End Sub
End Module

이 코드는 다음을 표시합니다.

F(Base)
F(Derived)

단순 식

단순 식은 리터럴, 괄호로 착색된 식, 인스턴스 식 또는 단순 이름 식입니다.

SimpleExpression
    : LiteralExpression
    | ParenthesizedExpression
    | InstanceExpression
    | SimpleNameExpression
    | AddressOfExpression
    ;

리터럴 식

리터럴 식은 리터럴이 나타내는 값으로 계산됩니다. 리터럴 식은 기본값으로 분류되는 리터럴 Nothing을 제외하고 값으로 분류됩니다.

LiteralExpression
    : Literal
    ;

괄호로 착색된 식

괄호로 묶인 식은 괄호로 묶인 식으로 구성됩니다. 괄호로 묶인 식은 값으로 분류되고 묶은 식은 값으로 분류되어야 합니다. 괄호가 있는 식은 괄호 안에 있는 식의 값으로 계산됩니다.

ParenthesizedExpression
    : OpenParenthesis Expression CloseParenthesis
    ;

인스턴스 식

인스턴스 식은 키워드Me입니다. 공유되지 않은 메서드, 생성자 또는 속성 접근자의 본문 내에서만 사용할 수 있습니다. 값으로 분류됩니다. 키워드 Me 는 실행 중인 메서드 또는 속성 접근자를 포함하는 형식의 인스턴스를 나타냅니다. 생성자가 다른 생성자(섹션 생성자) Me 를 명시적으로 호출하는 경우 인스턴스가 아직 생성되지 않았기 때문에 해당 생성자 호출 이후까지 사용할 수 없습니다.

InstanceExpression
    : 'Me'
    ;

단순 이름 식

간단한 이름 식은 단일 식별자 뒤에 선택적 형식 인수 목록으로 구성됩니다.

SimpleNameExpression
    : Identifier ( OpenParenthesis 'Of' TypeArgumentList CloseParenthesis )?
    ;

이름은 다음 "단순 이름 확인 규칙"으로 확인되고 분류됩니다.

  1. 즉시 바깥쪽 블록부터 시작하여 바깥쪽에 있는 각 블록(있는 경우)을 계속합니다. 식별자가 지역 변수, 정적 변수, 상수 로컬, 메서드 형식 매개 변수 또는 매개 변수의 이름과 일치하는 경우 식별자는 일치하는 엔터티를 참조합니다.

    식별자가 지역 변수, 정적 변수 또는 상수 로컬과 일치하고 형식 인수 목록이 제공된 경우 컴파일 시간 오류가 발생합니다. 식별자가 메서드 형식 매개 변수와 일치하고 형식 인수 목록이 제공된 경우 일치하는 항목이 없고 확인이 계속됩니다. 식별자가 지역 변수와 일치하면 일치하는 지역 변수는 암시적 함수 또는 Get 접근자 반환 지역 변수이고 식은 호출 식, 호출 문 또는 AddressOf 식의 일부이며 일치가 발생하지 않고 해결이 계속됩니다.

    식은 지역 변수, 정적 변수 또는 매개 변수인 경우 변수로 분류됩니다. 식이 메서드 형식 매개 변수인 경우 형식으로 분류됩니다. 식은 상수 로컬인 경우 값으로 분류됩니다.

  2. 식이 포함된 중첩된 각 형식에 대해 가장 안쪽에서 시작하여 가장 바깥쪽으로 이동하며, 형식의 식별자를 조회하면 액세스 가능한 멤버와 일치하는 항목이 생성됩니다.

    1. 일치하는 형식 멤버가 형식 매개 변수인 경우 결과는 형식으로 분류되고 일치하는 형식 매개 변수입니다. 형식 인수 목록이 제공된 경우 일치하는 항목이 없고 해결 방법이 계속됩니다.
    2. 그렇지 않으면 형식이 즉시 바깥쪽 형식이고 조회가 공유되지 않는 형식 멤버를 식별하는 경우 결과는 형식 Me.E(Of A)의 멤버 액세스와 동일합니다. 여기서 E 식별자는 A 형식 인수 목록입니다(있는 경우).
    3. 그렇지 않으면 결과는 일치하는 멤버를 포함하는 형식이 식별자이며 형식 인수 목록(있는 T 경우)인 폼T.E(Of A)의 멤버 E 액세스와 A 정확히 동일합니다. 이 경우 식별자가 공유되지 않은 멤버를 참조하는 것은 오류입니다.
  3. 가장 안쪽에서 시작하여 가장 바깥쪽 네임스페이스로 가는 중첩된 각 네임스페이스에 대해 다음을 수행합니다.

    1. 네임스페이스에 지정된 이름의 액세스 가능한 형식이 포함되어 있고 형식 인수 목록에 제공된 것과 동일한 수의 형식 매개 변수가 있는 경우 식별자는 해당 형식을 참조하고 형식으로 분류됩니다.
    2. 그렇지 않으면 형식 인수 목록이 제공되지 않았고 네임스페이스에 지정된 이름의 네임스페이스 멤버가 포함된 경우 식별자는 해당 네임스페이스를 참조하고 네임스페이스로 분류됩니다.
    3. 그렇지 않은 경우 네임스페이스에 하나 이상의 액세스 가능한 표준 모듈이 포함되어 있고 식별자의 멤버 이름 조회가 정확히 하나의 표준 모듈에서 액세스 가능한 일치 항목을 생성하는 경우 결과는 일치하는 멤버를 포함하는 표준 모듈이 식별자이며 형식 인수 목록인 양식 M.E(Of A)M 의 멤버 E 액세스와 A 정확히 동일합니다. 있는 경우 식별자가 둘 이상의 표준 모듈에서 액세스 가능한 형식 멤버와 일치하면 컴파일 시간 오류가 발생합니다.
  4. 원본 파일에 가져오기 별칭이 하나 이상 있고 식별자가 그 중 하나의 이름과 일치하는 경우 식별자는 해당 네임스페이스 또는 형식을 참조합니다. 형식 인수 목록을 제공하면 컴파일 시간 오류가 발생합니다.

  5. 이름 참조를 포함하는 원본 파일에 하나 이상의 가져오기가 있는 경우:

    1. 식별자가 정확히 한 개에서 일치하는 경우 형식 인수 목록에 제공된 것과 동일한 수의 형식 매개 변수를 사용하여 액세스 가능한 형식의 이름을 가져오거나 형식 멤버가 있는 경우 식별자는 해당 형식 또는 형식 멤버를 참조합니다. 식별자가 둘 이상 일치하면 형식 인수 목록에 제공된 것과 동일한 수의 형식 매개 변수가 있는 액세스 가능한 형식의 이름을 가져오거나 액세스할 수 있는 형식 멤버가 있는 경우 컴파일 시간 오류가 발생합니다.
    2. 그렇지 않은 경우 형식 인수 목록이 제공되지 않았고 식별자가 정확히 한 개에서 일치하는 경우 액세스 가능한 형식이 있는 네임스페이스의 이름을 가져오면 식별자가 해당 네임스페이스를 참조합니다. 형식 인수 목록이 제공되지 않았고 식별자가 둘 이상 일치하는 경우 액세스 가능한 형식이 있는 네임스페이스의 이름을 가져오면 컴파일 시간 오류가 발생합니다.
    3. 그렇지 않은 경우 가져오기에 하나 이상의 액세스 가능한 표준 모듈이 포함되어 있고 식별자의 멤버 이름 조회가 정확히 하나의 표준 모듈에서 액세스 가능한 일치 항목을 생성하는 경우 결과는 일치하는 멤버를 포함하는 표준 모듈이 식별자이며 형식 인수 목록인 양식 M.E(Of A)M 의 멤버 E 액세스와 A 정확히 동일합니다. 있는 경우 식별자가 둘 이상의 표준 모듈에서 액세스 가능한 형식 멤버와 일치하면 컴파일 시간 오류가 발생합니다.
  6. 컴파일 환경에서 하나 이상의 가져오기 별칭을 정의하고 식별자가 해당 별칭 중 하나의 이름과 일치하는 경우 식별자는 해당 네임스페이스 또는 형식을 참조합니다. 형식 인수 목록을 제공하면 컴파일 시간 오류가 발생합니다.

  7. 컴파일 환경에서 하나 이상의 가져오기를 정의하는 경우:

    1. 식별자가 정확히 한 개에서 일치하는 경우 형식 인수 목록에 제공된 것과 동일한 수의 형식 매개 변수를 사용하여 액세스 가능한 형식의 이름을 가져오거나 형식 멤버가 있는 경우 식별자는 해당 형식 또는 형식 멤버를 참조합니다. 식별자가 둘 이상 일치하면 형식 인수 목록에 제공된 것과 동일한 수의 형식 매개 변수를 사용하여 액세스할 수 있는 형식의 이름을 가져오거나 형식 멤버가 있는 경우 컴파일 시간 오류가 발생합니다.
    2. 그렇지 않은 경우 형식 인수 목록이 제공되지 않았고 식별자가 정확히 한 개에서 일치하는 경우 액세스 가능한 형식이 있는 네임스페이스의 이름을 가져오면 식별자가 해당 네임스페이스를 참조합니다. 형식 인수 목록이 제공되지 않았고 식별자가 둘 이상 일치하는 경우 액세스 가능한 형식이 있는 네임스페이스의 이름을 가져오면 컴파일 시간 오류가 발생합니다.
    3. 그렇지 않은 경우 가져오기에 하나 이상의 액세스 가능한 표준 모듈이 포함되어 있고 식별자의 멤버 이름 조회가 정확히 하나의 표준 모듈에서 액세스 가능한 일치 항목을 생성하는 경우 결과는 일치하는 멤버를 포함하는 표준 모듈이 식별자이며 형식 인수 목록인 양식 M.E(Of A)M 의 멤버 E 액세스와 A 정확히 동일합니다. 있는 경우 식별자가 둘 이상의 표준 모듈에서 액세스 가능한 형식 멤버와 일치하면 컴파일 시간 오류가 발생합니다.
  8. 그렇지 않으면 식별자가 지정한 이름이 정의되지 않습니다.

정의되지 않은 간단한 이름 식은 컴파일 시간 오류입니다.

일반적으로 이름은 특정 네임스페이스에서 한 번만 발생할 수 있습니다. 그러나 여러 .NET 어셈블리에서 네임스페이스를 선언할 수 있으므로 두 어셈블리가 동일한 정규화된 이름의 형식을 정의하는 상황이 발생할 수 있습니다. 이 경우 현재 소스 파일 집합에 선언된 형식이 외부 .NET 어셈블리에 선언된 형식보다 선호됩니다. 그렇지 않으면 이름이 모호하며 이름을 명확하게 구분할 방법이 없습니다.

AddressOf 식

AddressOf 은 메서드 포인터를 생성하는 데 사용됩니다. 식은 메서드 그룹 또는 런타임에 AddressOf 바인딩된 액세스로 분류해야 하는 키워드 및 식으로 구성됩니다. 메서드 그룹은 생성자를 참조할 수 없습니다.

결과는 메서드 그룹과 동일한 연결된 대상 식 및 형식 인수 목록(있는 경우)을 사용하여 메서드 포인터로 분류됩니다.

AddressOfExpression
    : 'AddressOf' Expression
    ;

형식 식

형식 식GetType 식, 식, TypeOf...IsIs 식 또는 식입니다GetXmlNamespace.

TypeExpression
    : GetTypeExpression
    | TypeOfIsExpression
    | IsExpression
    | GetXmlNamespaceExpression
    ;

GetType 식

식은 GetType 키워드 GetType 와 형식의 이름으로 구성됩니다.

GetTypeExpression
    : 'GetType' OpenParenthesis GetTypeTypeName CloseParenthesis
    ;

GetTypeTypeName
    : TypeName
    | QualifiedOpenTypeName
    ;

QualifiedOpenTypeName
    : Identifier TypeArityList? (Period IdentifierOrKeyword TypeArityList?)*
    | 'Global' Period IdentifierOrKeyword TypeArityList?
      (Period IdentifierOrKeyword TypeArityList?)*
    ;

TypeArityList
    : OpenParenthesis 'Of' CommaList? CloseParenthesis
    ;

CommaList
    : Comma Comma*
    ;

GetType 식은 값으로 분류되고 해당 값은 GetTypeTypeName을 나타내는 리플렉션(System.Type) 클래스입니다. GetTypeTypeName이 형식 매개 변수인 경우 식은 런타임에 형식 매개 변수에 대해 제공된 형식 인수에 해당하는 개체를 반환 System.Type 합니다.

GetTypeTypeName은 다음과 같은 두 가지 방법으로 특별합니다.

  • 이 형식 이름을 참조할 System.Void수 있는 언어의 유일한 위치인 것으로 허용됩니다.

  • 형식 인수가 생략된 생성된 제네릭 형식일 수 있습니다. 이렇게 하면 식에서 GetType 제네릭 형식 자체에 System.Type 해당하는 개체를 반환할 수 있습니다.

다음 예제에서는 식을 보여 줍니다 GetType .

Module Test
    Sub Main()
        Dim t As Type() = { GetType(Integer), GetType(System.Int32), _
            GetType(String), GetType(Double()) }
        Dim i As Integer

        For i = 0 To t.Length - 1
            Console.WriteLine(t(i).Name)
        Next i
    End Sub
End Module

결과 출력은 다음과 같습니다.

Int32
Int32
String
Double[]

TypeOf... 식입니다.

TypeOf...Is 식은 값의 런타임 형식이 지정된 형식과 호환되는지 여부를 확인하는 데 사용됩니다. 첫 번째 피연산자는 값으로 분류되어야 하고, 재분류된 람다 메서드일 수 없으며, 참조 형식 또는 제약이 없는 형식 매개 변수 형식이어야 합니다. 두 번째 피연산자는 형식 이름이어야 합니다. 식의 결과는 값으로 분류되고 값입니다 Boolean . 식은 피연산자의 런타임 형식에 ID, 기본값, 참조, 배열, 값 형식 또는 형식 False 매개 변수 변환이 있는지 여부를 계산 True 합니다. 식의 형식과 특정 형식 간에 변환이 없는 경우 컴파일 시간 오류가 발생합니다.

TypeOfIsExpression
    : 'TypeOf' Expression 'Is' LineTerminator? TypeName
    ;

식입니다.

Is 또는 IsNot 식은 참조 같음 비교를 수행하는 데 사용됩니다.

IsExpression
    : Expression 'Is' LineTerminator? Expression
    | Expression 'IsNot' LineTerminator? Expression
    ;

각 식은 값으로 분류되어야 하며 각 식의 형식은 참조 형식, 제약이 없는 형식 매개 변수 형식 또는 nullable 값 형식이어야 합니다. 그러나 한 식의 형식이 제약이 없는 형식 매개 변수 형식이거나 null 허용 값 형식인 경우 다른 식은 리터럴 Nothing이어야 합니다.

결과는 값으로 분류되고 다음과 같이 Boolean입력됩니다. Is 작업은 두 값이 동일한 인스턴스를 True 참조하는지 아니면 두 값이 모두 같은지 또는 False 그렇지 않은지 평가합니다Nothing. IsNot 작업은 두 값이 동일한 인스턴스를 False 참조하는지 아니면 두 값이 모두 같은지 또는 True 그렇지 않은지 평가합니다Nothing.

GetXmlNamespace 식

식은 GetXmlNamespace 소스 파일 또는 컴파일 환경에서 선언한 XML 네임스페이스의 키워드 GetXmlNamespace 와 이름으로 구성됩니다.

GetXmlNamespaceExpression
    : 'GetXmlNamespace' OpenParenthesis XMLNamespaceName? CloseParenthesis
    ;

GetXmlNamespace 식은 값으로 분류되고 해당 값은 XMLNamespaceName을 나타내는 인스턴스 System.Xml.Linq.XNamespace 입니다. 해당 형식을 사용할 수 없는 경우 컴파일 시간 오류가 발생합니다.

다음은 그 예입니다.

Imports <xmlns:db="http://example.org/database">

Module Test
    Sub Main()
        Dim db = GetXmlNamespace(db)

        ' The following are equivalent
        Dim customer1 = _
            New System.Xml.Linq.XElement(db + "customer", "Bob")
        Dim customer2 = <db:customer>Bob</>
    End Sub
End Module

괄호 사이의 모든 항목은 네임스페이스 이름의 일부로 간주되므로 공백과 같은 항목에 대한 XML 규칙이 적용됩니다. 다음은 그 예입니다.

Imports <xmlns:db-ns="http://example.org/database">

Module Test
    Sub Main()

        ' Error, XML name expected
        Dim db1 = GetXmlNamespace( db-ns )

        ' Error, ')' expected
        Dim db2 = GetXmlNamespace(db _
            )

        ' OK.
        Dim db3 = GetXmlNamespace(db-ns)
    End Sub
End Module

XML 네임스페이스 식을 생략할 수도 있습니다. 이 경우 식은 기본 XML 네임스페이스를 나타내는 개체를 반환합니다.

멤버 액세스 식

멤버 액세스 식은 엔터티의 멤버에 액세스하는 데 사용됩니다.

MemberAccessExpression
    : MemberAccessBase? Period IdentifierOrKeyword
      ( OpenParenthesis 'Of' TypeArgumentList CloseParenthesis )?
    ;

MemberAccessBase
    : Expression
    | NonArrayTypeName
    | 'Global'
    | 'MyClass'
    | 'MyBase'
    ;

식, E 배열이 아닌 형식 이름, 키워드 Global또는 생략되고 I 선택적 형식 인수 목록이 A있는 식별자인 폼E.I(Of A)의 멤버 액세스는 다음과 같이 평가되고 분류됩니다.

  1. 생략하면 E 즉시 포함된 With 문의 식이 대체 E 되고 멤버 액세스가 수행됩니다. 포함하는 With 문이 없으면 컴파일 시간 오류가 발생합니다.

  2. 네임스페이스로 분류되거나 E 키워드Global인 경우 E 멤버 조회는 지정된 네임스페이스의 컨텍스트에서 수행됩니다. 형식 인수 목록에 제공된 것과 동일한 수의 형식 매개 변수가 있는 해당 네임스페이스의 액세스 가능한 멤버 이름인 경우 I 결과는 해당 멤버입니다. 결과는 멤버에 따라 네임스페이스 또는 형식으로 분류됩니다. 그렇지 않으면 컴파일 시간 오류가 발생합니다.

  3. 형식 또는 형식으로 분류된 식인 경우 E 멤버 조회는 지정된 형식의 컨텍스트에서 수행됩니다. 액세스 가능한 멤버 EE.I 의 이름인 경우 I 다음과 같이 평가되고 분류됩니다.

    1. I 키워드 New 이고 E 열거형이 아니면 컴파일 시간 오류가 발생합니다.
    2. 형식 인수 목록에 제공된 형식 매개 변수 수가 동일한 형식을 식별하는 경우 I 결과가 해당 형식입니다.
    3. 하나 이상의 메서드를 식별하는 경우 I 결과는 연결된 형식 인수 목록이 있고 연결된 대상 식이 없는 메서드 그룹입니다.
    4. 하나 이상의 속성을 식별하고 형식 인수 목록이 제공되지 않은 경우 I 결과는 연결된 대상 식이 없는 속성 그룹입니다.
    5. 공유 변수를 식별하고 형식 인수 목록이 제공되지 않은 경우 I 결과는 변수 또는 값입니다. 변수가 읽기 전용이고 참조가 변수가 선언된 형식의 공유 생성자 외부에서 발생하는 경우 결과는 공유 변수 IE의 값입니다. 그렇지 않으면 결과는 .의 공유 변수 I 입니다 E.
    6. 공유 이벤트를 식별하고 형식 인수 목록이 제공되지 않은 경우 I 결과는 연결된 대상 식이 없는 이벤트 액세스입니다.
    7. 상수와 형식 인수 목록이 제공되지 않은 경우 I 결과는 해당 상수의 값입니다.
    8. 열거형 멤버를 식별하고 형식 인수 목록이 제공되지 않은 경우 I 결과는 해당 열거형 멤버의 값입니다.
    9. 그렇지 않으면 E.I 잘못된 멤버 참조이며 컴파일 시간 오류가 발생합니다.
  4. 변수 또는 값으로 분류되는 경우 E 해당 형식은 T멤버 조회가 컨텍스트 T에서 수행됩니다. 액세스 가능한 멤버 TE.I 의 이름인 경우 I 다음과 같이 평가되고 분류됩니다.

    1. 키워드, 즉 형식 MyClassMyBase인수가 Me제공되지 않은 경우 I 결과는 연결된 대상 식 E 이 있고 형식 인수 목록이 없는 형식의 E 인스턴스 생성자를 나타내는 메서드 그룹입니다. ENew 그렇지 않으면 컴파일 시간 오류가 발생합니다.
    2. 확장 메서드가 아닌 Object경우 T 확장 메서드를 포함하여 하나 이상의 메서드를 식별하는 경우 I 결과는 연결된 형식 인수 목록과 연결된 대상 식이 E있는 메서드 그룹입니다.
    3. 하나 이상의 속성을 식별하고 형식 인수가 제공되지 않은 경우 I 결과는 연결된 대상 식 E이 있는 속성 그룹입니다.
    4. 공유 변수 또는 인스턴스 변수를 식별하고 형식 인수가 제공되지 않은 경우 I 결과는 변수 또는 값입니다. 변수가 읽기 전용이고 변수가 변수 종류(공유 또는 인스턴스)에 적합하게 선언된 클래스의 생성자 외부에서 참조가 발생하는 경우 결과는 참조되는 E개체의 변수 I 값입니다. 참조 형식인 경우 T 결과는 .에서 참조하는 E개체의 변수 I 입니다. 그렇지 않으면 T 값 형식이고 식 E 이 변수로 분류되면 결과는 변수이고, 그렇지 않으면 결과는 값입니다.
    5. 이벤트를 식별하고 형식 인수가 제공되지 않은 경우 I 결과는 연결된 대상 식 E이 있는 이벤트 액세스입니다.
    6. 상수와 형식 인수가 제공되지 않은 경우 I 결과는 해당 상수의 값입니다.
    7. 열거형 멤버를 식별하고 형식 인수가 제공되지 않은 경우 I 결과는 해당 열거형 멤버의 값입니다.
    8. Object경우 T 결과는 연결된 형식 인수 목록 및 연결된 대상 식인 런타임에 바인딩된 액세스로 분류된 런타임에 바인딩된 멤버 조회입니다E.
  5. 그렇지 않으면 E.I 잘못된 멤버 참조이며 컴파일 시간 오류가 발생합니다.

MyClass.I(Of A) 의 멤버 액세스는 동일 Me.I(Of A)하지만 폼에 액세스하는 모든 멤버는 멤버를 재정의할 수 없는 것처럼 처리됩니다. 따라서 액세스하는 멤버는 멤버에 액세스하는 값의 런타임 형식에 의해 영향을 받지 않습니다.

MyBase.I(Of A) 의 멤버 액세스는 멤버 액세스 식을 포함하는 형식의 직접 기본 형식인 위치 T 와 동일합니다CType(Me, T).I(Of A). 호출되는 메서드를 재정의할 수 없는 것처럼 모든 메서드 호출이 처리됩니다. 이 형식의 멤버 액세스는 기본 액세스라고도 합니다.

다음 예제에서는 관련 방법을 MeMyBase 보여 줍니다MyClass.

Class Base
    Public Overridable Sub F()
        Console.WriteLine("Base.F")
    End Sub
End Class

Class Derived
    Inherits Base

    Public Overrides Sub F()
        Console.WriteLine("Derived.F")
    End Sub

    Public Sub G()
        MyClass.F()
    End Sub
End Class

Class MoreDerived
    Inherits Derived

    Public Overrides Sub F()
        Console.WriteLine("MoreDerived.F")
    End Sub

    Public Sub H()
        MyBase.F()
    End Sub
End Class

Module Test
    Sub Main()
        Dim x As MoreDerived = new MoreDerived()

        x.F()
        x.G()
        x.H()
    End Sub

End Module

이 코드는 다음을 출력합니다.

MoreDerived.F
Derived.F
Derived.F

멤버 액세스 식이 키워드 Global로 시작되면 키워드는 이름 없는 가장 바깥쪽 네임스페이스를 나타내며, 선언이 바깥쪽 네임스페이스를 숨기는 경우에 유용합니다. 키 Global 워드를 사용하면 해당 상황에서 가장 바깥쪽 네임스페이스로 "이스케이프"할 수 있습니다. 다음은 그 예입니다.

Class System
End Class

Module Test
    Sub Main()
        ' Error: Class System does not contain Console
        System.Console.WriteLine("Hello, world!") 


        ' Legal, binds to System in outermost namespace
        Global.System.Console.WriteLine("Hello, world!") 
    End Sub
End Module

위의 예제에서는 식별자가 System 네임스페이스가 System아닌 클래스System에 바인딩되므로 첫 번째 메서드 호출이 유효하지 않습니다. 네임스페이스에 System 액세스하는 유일한 방법은 가장 바깥쪽 네임 Global 스페이스로 이스케이프하는 것입니다.

액세스 중인 멤버가 공유되는 경우 마침표의 왼쪽에 있는 식은 불필요하며 멤버 액세스가 런타임에 바인딩되지 않는 한 평가되지 않습니다. 예를 들어 다음 코드를 고려합니다.

Class C
    Public Shared F As Integer = 10
End Class

Module Test
    Public Function ReturnC() As C
        Console.WriteLine("Returning a new instance of C.")
        Return New C()
    End Function

    Public Sub Main()
        Console.WriteLine("The value of F is: " & ReturnC().F)
    End Sub
End Module

공유 멤버FThe value of F is: 10 액세스하는 인스턴스 C 를 제공하기 위해 함수 ReturnC 를 호출할 필요가 없기 때문에 출력됩니다.

동일한 형식 및 멤버 이름

형식과 동일한 이름을 사용하여 멤버의 이름을 지정하는 것은 드문 일이 아닙니다. 그러나 이 경우 불편한 이름 숨기기가 발생할 수 있습니다.

Enum Color
    Red
    Green
    Yellow
End Enum

Class Test
    ReadOnly Property Color() As Color
        Get
            Return Color.Red
        End Get
    End Property

    Shared Function DefaultColor() As Color
        Return Color.Green    ' Binds to the instance property!
    End Function
End Class

이전 예제에서 단순 이름은 ColorDefaultColor 형식 대신 인스턴스 속성에 바인딩됩니다. 인스턴스 멤버는 공유 멤버에서 참조할 수 없으므로 일반적으로 오류가 발생합니다.

그러나 특수 규칙은 이 경우 형식에 대한 액세스를 허용합니다. 멤버 액세스 식의 기본 식이 단순 이름이며 형식의 이름이 같은 상수, 필드, 속성, 지역 변수 또는 매개 변수에 바인딩하는 경우 기본 식은 멤버 또는 형식을 참조할 수 있습니다. 둘 중 하나에서 액세스할 수 있는 멤버가 동일하기 때문에 모호성이 발생할 수 없습니다.

기본 인스턴스

경우에 따라 일반적으로 공통 기본 클래스에서 파생된 클래스 또는 항상 단일 인스턴스만 있습니다. 예를 들어 사용자 인터페이스에 표시되는 대부분의 창에는 언제든지 화면에 하나의 인스턴스만 표시됩니다. 이러한 유형의 클래스 작업을 간소화하기 위해 Visual Basic은 각 클래스에 대해 쉽게 참조할 수 있는 단일 인스턴스를 제공하는 클래스의 기본 인스턴스를 자동으로 생성할 수 있습니다.

기본 인스턴스는 항상 특정 형식이 아닌 형식 패밀리 에 대해 만들어집니다. 따라서 Form에서 파생되는 Form1 클래스에 대한 기본 인스턴스를 만드는 대신 Form에서 파생된 모든 클래스에 대해 기본 인스턴스가 만들어집니다. 즉, 기본 클래스에서 파생되는 각 개별 클래스는 기본 인스턴스를 갖도록 특별히 표시할 필요가 없습니다.

클래스의 기본 인스턴스는 해당 클래스의 기본 인스턴스를 반환하는 컴파일러 생성 속성으로 표시됩니다. 특정 기본 클래스에서 파생된 모든 클래스의 기본 인스턴스 할당 및 삭제를 관리하는 그룹 클래스라는 클래스의 멤버로 생성된 속성입니다. 예를 들어 파생된 Form 클래스의 모든 기본 인스턴스 속성을 클래스에서 MyForms 수집할 수 있습니다. 그룹 클래스의 인스턴스가 식My.Forms에서 반환되는 경우 다음 코드는 파생 클래스의 기본 인스턴스에 액세스하고 Form2다음을 수행합니다.Form1

Class Form1
    Inherits Form
    Public x As Integer
End Class

Class Form2
    Inherits Form
    Public y As Integer
End Class

Module Main
    Sub Main()
        My.Forms.Form1.x = 10
        Console.WriteLine(My.Forms.Form2.y)
    End Sub
End Module

기본 인스턴스는 첫 번째 참조가 될 때까지 만들어지지 않습니다. 기본 인스턴스를 나타내는 속성을 페치하면 기본 인스턴스가 아직 만들어지지 않았거나 설정 Nothing되지 않은 경우 기본 인스턴스가 만들어집니다. 기본 인스턴스의 존재 여부를 테스트할 수 있도록 하려면 기본 인스턴스가 또는 IsNot 연산자의 Is 대상인 경우 기본 인스턴스가 만들어지지 않습니다. 따라서 기본 인스턴스를 만들지 않고 기본 인스턴스 Nothing 인지 아니면 다른 참조인지 테스트할 수 있습니다.

기본 인스턴스는 기본 인스턴스가 있는 클래스 외부에서 기본 인스턴스를 쉽게 참조할 수 있도록 하기 위한 것입니다. 정의한 클래스 내에서 기본 인스턴스를 사용하면 참조되는 인스턴스(예: 기본 인스턴스 또는 현재 인스턴스)에 대한 혼동이 발생할 수 있습니다. 예를 들어 다음 코드는 다른 인스턴스에서 호출되더라도 기본 인스턴스의 값 x 만 수정합니다. 따라서 코드는 다음 대신 값을 5 출력합니다 10.

Class Form1
    Inherits Form

    Public x As Integer = 5

    Public Sub ChangeX()
        Form1.x = 10
    End Sub
End Class

Module Main
    Sub Main()
        Dim f As Form1 = New Form1()
        f.ChangeX()
        Console.WriteLine(f.x)
    End Sub
End Module

이러한 종류의 혼동을 방지하기 위해 기본 인스턴스 형식의 인스턴스 메서드 내에서 기본 인스턴스를 참조하는 것은 유효하지 않습니다.

기본 인스턴스 및 형식 이름

기본 인스턴스는 해당 형식의 이름을 통해 직접 액세스할 수도 있습니다. 이 경우 형식 이름이 허용되지 E않는 식 컨텍스트에서는 기본 인스턴스가 있는 E 클래스의 정규화된 이름을 나타내는 식이 기본 인스턴스 속성을 가져오는 식을 나타내는 식으로 변경 E'E' 됩니다. 예를 들어 형식 이름을 통해 기본 인스턴스에 액세스할 수 있도록 허용에서 Form 파생된 클래스의 기본 인스턴스인 경우 다음 코드는 이전 예제의 코드와 동일합니다.

Module Main
    Sub Main()
        Form1.x = 10
        Console.WriteLine(Form2.y)
    End Sub
End Module

즉, 형식의 이름을 통해 액세스할 수 있는 기본 인스턴스도 형식 이름을 통해 할당할 수 있습니다. 예를 들어 다음 코드는 기본 인스턴스 Form1 를 다음으로 Nothing설정합니다.

Module Main
    Sub Main()
        Form1 = Nothing
    End Sub
End Module

의미는 E.IE 클래스를 나타내며 I 공유 멤버를 나타내는 것은 변경되지 않습니다. 이러한 식은 여전히 클래스 인스턴스에서 직접 공유 멤버에 액세스하며 기본 인스턴스를 참조하지 않습니다.

그룹 클래스

이 특성은 Microsoft.VisualBasic.MyGroupCollectionAttribute 기본 인스턴스 패밀리에 대한 그룹 클래스를 나타냅니다. 특성에는 다음과 같은 네 개의 매개 변수가 있습니다.

  • 매개 변수 TypeToCollect 는 그룹의 기본 클래스를 지정합니다. 형식 매개 변수에 관계없이 이 이름을 가진 형식에서 파생되는 열린 형식 매개 변수가 없는 모든 인스턴스화 가능한 클래스에는 자동으로 기본 인스턴스가 있습니다.

  • 매개 변수 CreateInstanceMethodName 는 기본 인스턴스 속성에 새 인스턴스를 만들기 위해 그룹 클래스에서 호출할 메서드를 지정합니다.

  • 매개 변수 DisposeInstanceMethodName 는 기본 인스턴스 속성에 값 Nothing이 할당된 경우 기본 인스턴스 속성을 삭제하기 위해 그룹 클래스에서 호출할 메서드를 지정합니다.

  • 매개 변수 DefaultInstanceAlias 는 기본 인스턴스가 해당 형식 이름을 통해 직접 액세스할 수 있는 경우 클래스 이름을 대체하도록 식을 E' 지정합니다. 이 매개 변수가 Nothing 빈 문자열인 경우 이 그룹 형식의 기본 인스턴스는 해당 형식의 이름을 통해 직접 액세스할 수 없습니다. (참고. Visual Basic 언어 DefaultInstanceAlias 의 모든 현재 구현에서 매개 변수는 컴파일러 제공 코드를 제외하고 무시됩니다.)

처음 세 매개 변수에서 쉼표로 형식과 메서드의 이름을 구분하여 여러 형식을 동일한 그룹으로 수집할 수 있습니다. 각 매개 변수에 동일한 수의 항목이 있어야 하며 목록 요소가 순서대로 일치합니다. 예를 들어 다음 특성 선언은 파생되는 C1형식을 C2 수집하거나 C3 단일 그룹으로 수집합니다.

<Microsoft.VisualBasic.MyGroupCollection("C1, C2, C3", _
    "CreateC1, CreateC2, CreateC3", _
    "DisposeC1, DisposeC2, DisposeC3", "My.Cs")>
Public NotInheritable Class MyCs
    ...
End Class

create 메서드의 서명은 폼 Shared Function <Name>(Of T As {New, <Type>})(Instance Of T) As T이어야 합니다. dispose 메서드는 형식 Shared Sub <Name>(Of T As <Type>)(ByRef Instance Of T)이어야 합니다. 따라서 이전 섹션의 예제에 대한 그룹 클래스를 다음과 같이 선언할 수 있습니다.

<Microsoft.VisualBasic.MyGroupCollection("Form", "Create", _
    "Dispose", "My.Forms")> _
Public NotInheritable Class MyForms
    Private Shared Function Create(Of T As {New, Form}) _
        (Instance As T) As T
        If Instance Is Nothing Then
            Return New T()
        Else
            Return Instance
        End If
    End Function

    Private Shared Sub Dispose(Of T As Form)(ByRef Instance As T)
        Instance.Close()
        Instance = Nothing
    End Sub
End Class

원본 파일이 파생 클래스 Form1를 선언한 경우 생성된 그룹 클래스는 다음과 같습니다.

<Microsoft.VisualBasic.MyGroupCollection("Form", "Create", _
    "Dispose", "My.Forms")> _
Public NotInheritable Class MyForms
    Private Shared Function Create(Of T As {New, Form}) _
        (Instance As T) As T
        If Instance Is Nothing Then
            Return New T()
        Else
            Return Instance
        End If
    End Function

    Private Shared Sub Dispose(Of T As Form)(ByRef Instance As T)
        Instance.Close()
        Instance = Nothing
    End Sub

    Private m_Form1 As Form1

    Public Property Form1() As Form1
        Get
            Return Create(m_Form1)
        End Get
        Set (Value As Form1)
            If Value IsNot Nothing AndAlso Value IsNot m_Form1 Then
                Throw New ArgumentException( _
                    "Property can only be set to Nothing.")
            End If
            Dispose(m_Form1)
        End Set
    End Property
End Class

Extension 메서드 컬렉션

멤버 액세스 식 E.I 에 대한 확장 메서드는 현재 컨텍스트에서 사용할 수 있는 이름으로 I 모든 확장 메서드를 수집하여 수집됩니다.

  1. 먼저 식을 포함하는 중첩된 각 형식이 가장 안쪽에서 시작하여 가장 바깥쪽으로 이동하여 선택됩니다.
  2. 그런 다음, 가장 안쪽에서 시작하여 가장 바깥쪽 네임스페이스로 이동하여 중첩된 각 네임스페이스를 확인합니다.
  3. 그런 다음 원본 파일의 가져오기를 확인합니다.
  4. 그런 다음 컴파일 환경에서 정의한 가져오기를 확인합니다.

확장 메서드는 대상 식 형식에서 확장 메서드의 첫 번째 매개 변수 형식으로 확장 네이티브 변환이 있는 경우에만 수집됩니다. 일반 단순 이름 식 바인딩과 달리 검색은 모든 확장 메서드를 수집합니다. 확장 메서드를 찾을 때 컬렉션이 중지되지 않습니다. 다음은 그 예입니다.

Imports System.Runtime.CompilerServices

Class C1
End Class


Namespace N1
    Module N1C1Extensions
        <Extension> _
        Sub M1(c As C1, x As Integer)
        End Sub
    End Module
End Namespace

Namespace N1.N2
    Module N2C1Extensions
        <Extension> _
        Sub M1(c As C1, y As Double)
        End Sub
    End Module
End Namespace

Namespace N1.N2.N3
    Module Test
        Sub Main()
            Dim x As New C1()

            ' Calls N1C1Extensions.M1
            x.M1(10)
        End Sub
    End Module
End Namespace

이 예제에서는 이전에 N1C1Extensions.M1발견되었지만 N2C1Extensions.M1 둘 다 확장 메서드로 간주됩니다. 모든 확장 메서드가 수집되면 해당 메서드는 재정의됩니다. Currying은 확장 메서드 호출의 대상을 가져와 확장 메서드 호출에 적용하여 첫 번째 매개 변수가 제거된 새 메서드 시그니처가 생성됩니다(지정되었기 때문). 다음은 그 예입니다.

Imports System.Runtime.CompilerServices

Module Ext1
    <Extension> _
    Sub M(x As Integer, y As Integer)
    End Sub
End Module

Module Ext2
    <Extension> _
    Sub M(x As Integer, y As Double)
    End Sub
End Module

Module Main
    Sub Test()
        Dim v As Integer = 10

        ' The curried method signatures considered are:
        '        Ext1.M(y As Integer)
        '        Ext2.M(y As Double)
        v.M(10)
    End Sub
End Module

위의 예제에서 적용 vExt1.M 의 커리 결과는 메서드 서명 Sub M(y As Integer)입니다.

확장 메서드의 첫 번째 매개 변수를 제거하는 것 외에도, 커리는 첫 번째 매개 변수 형식의 일부인 메서드 형식 매개 변수도 제거합니다. 메서드 형식 매개 변수를 사용하여 확장 메서드를 커링할 때 첫 번째 매개 변수에 형식 유추가 적용되고 유추되는 모든 형식 매개 변수에 대해 결과가 수정됩니다. 형식 유추에 실패하면 메서드가 무시됩니다. 다음은 그 예입니다.

Imports System.Runtime.CompilerServices

Module Ext1
    <Extension> _
    Sub M(Of T, U)(x As T, y As U)
    End Sub
End Module

Module Ext2
    <Extension> _
    Sub M(Of T)(x As T, y As T)
    End Sub
End Module

Module Main
    Sub Test()
        Dim v As Integer = 10

        ' The curried method signatures considered are:
        '        Ext1.M(Of U)(y As U)
        '        Ext2.M(y As Integer)
        v.M(10)
    End Sub
End Module

위의 예제에서는 형식 매개 변수 T 가 커리의 vExt1.M 결과로 유추되고 이제 고정되기 때문에 적용의 커리 결과가 메서드 서명Sub M(Of U)(y As U)입니다. 형식 매개 변수 U 가 커리의 일부로 유추되지 않았기 때문에 열린 매개 변수로 유지됩니다. 마찬가지로 형식 매개 변수 T 는 적용 Ext2.Mv 결과로 유추되므로 매개 변수 y 의 형식이 로 Integer고정됩니다. 다른 형식으로 유추되지 않습니다. 서명을 커링할 때 제약 조건을 제외한 New 모든 제약 조건도 적용됩니다. 제약 조건이 충족되지 않거나 커리의 일부로 유추되지 않은 형식에 따라 달라지면 확장 메서드가 무시됩니다. 다음은 그 예입니다.

Imports System.Runtime.CompilerServices

Module Ext1
    <Extension> _
    Sub M1(Of T As Structure)(x As T, y As Integer)
    End Sub

    <Extension> _
    Sub M2(Of T As U, U)(x As T, y As U)
    End Sub
End Module

Module Main
    Sub Test()
        Dim s As String = "abc"

        ' Error: String does not satisfy the Structure constraint
        s.M1(10)

        ' Error: T depends on U, which cannot be inferred
        s.M2(10)
    End Sub
End Module

메모. 확장 메서드의 커리를 수행하는 주된 이유 중 하나는 쿼리 패턴 메서드에 대한 인수를 평가하기 전에 쿼리 식이 반복 형식을 유추할 수 있기 때문입니다. 대부분의 쿼리 패턴 메서드는 형식 유추가 필요한 람다 식을 사용하므로 쿼리 식을 평가하는 프로세스가 크게 간소화됩니다.

일반 인터페이스 상속과 달리 서로 관련이 없는 두 인터페이스를 확장하는 확장 메서드는 동일한 커리 서명이 없는 한 사용할 수 있습니다.

Imports System.Runtime.CompilerServices

Interface I1
End Interface

Interface I2
End Interface

Class C1
    Implements I1, I2
End Class

Module I1Ext
    <Extension> _
    Sub M1(i As I1, x As Integer)
    End Sub

    <Extension> _
    Sub M2(i As I1, x As Integer)
    End Sub
End Module

Module I2Ext
    <Extension> _
    Sub M1(i As I2, x As Integer)
    End Sub

    <Extension> _
    Sub M2(I As I2, x As Double)
    End Sub
End Module

Module Main
    Sub Test()
        Dim c As New C1()

        ' Error: M is ambiguous between I1Ext.M1 and I2Ext.M1.
        c.M1(10)

        ' Calls I1Ext.M2
        c.M2(10)
    End Sub
End Module

마지막으로, 런타임에 바인딩을 수행할 때 확장 메서드는 고려되지 않는다는 점을 기억해야 합니다.

Module Test
    Sub Main()
        Dim o As Object = ...

        ' Ignores extension methods
        o.M1()
    End Sub
End Module

사전 멤버 액세스 식

사전 멤버 액세스 식은 컬렉션의 멤버를 조회하는 데 사용됩니다. 사전 멤버 액세스는 값 I 으로 분류되고 식별자인 식인 형식 E!IE 을 사용합니다.

DictionaryAccessExpression
    : Expression? '!' IdentifierOrKeyword
    ;

식의 형식에는 단일 String 매개 변수로 인덱싱된 기본 속성이 있어야 합니다. 사전 멤버 액세스 식 E!I 은 식 E.D("I")으로 변환됩니다. 여기서 D 는 기본 속성입니다 E. 다음은 그 예입니다.

Class Keys
    Public ReadOnly Default Property Item(s As String) As Integer
        Get
            Return 10
        End Get
    End Property 
End Class

Module Test
    Sub Main()
        Dim x As Keys = new Keys()
        Dim y As Integer
        ' The two statements are equivalent.
        y = x!abc
        y = x("abc")
    End Sub
End Module

식 없이 느낌표를 지정하면 즉시 포함된 With 문의 식이 가정됩니다. 포함하는 With 문이 없으면 컴파일 시간 오류가 발생합니다.

호출 식

호출 식은 호출 대상과 선택적 인수 목록으로 구성됩니다.

InvocationExpression
    : Expression ( OpenParenthesis ArgumentList? CloseParenthesis )?
    ;

ArgumentList
    : PositionalArgumentList
    | PositionalArgumentList Comma NamedArgumentList
    | NamedArgumentList
    ;

PositionalArgumentList
    : Expression? ( Comma Expression? )*
    ;

NamedArgumentList
    : IdentifierOrKeyword ColonEquals Expression
      ( Comma IdentifierOrKeyword ColonEquals Expression )*
    ;

대상 식은 메서드 그룹 또는 형식이 대리자 형식인 값으로 분류되어야 합니다. 대상 식이 대리자 형식인 값이면 호출 식의 대상이 대리자 형식의 멤버에 대한 Invoke 메서드 그룹이 되고 대상 식은 메서드 그룹의 연결된 대상 식이 됩니다.

인수 목록에는 위치 인수와 명명된 인수의 두 섹션이 있습니다. 위치 인수 는 식이며 명명된 인수 앞에 와야 합니다. 명명된 인수 는 키워드와 일치할 수 있는 식별자, 그 뒤에 식 := 으로 시작합니다.

메서드 그룹에 인스턴스 및 확장 메서드를 포함하여 액세스 가능한 메서드가 하나만 포함되어 있고 해당 메서드가 인수를 사용하지 않고 함수인 경우 메서드 그룹은 빈 인수 목록이 있는 호출 식으로 해석되고 결과는 제공된 인수 목록을 사용하여 호출 식의 대상으로 사용됩니다. 다음은 그 예입니다.

Class C1
    Function M1() As Integer()
        Return New Integer() { 1, 2, 3 }
    End Sub
End Class

Module Test
    Sub Main()
        Dim c As New C1()

        ' Prints 3
        Console.WriteLine(c.M1(2))
    End Sub
End Module

그렇지 않으면 지정된 인수 목록에 가장 적합한 메서드를 선택하기 위해 오버로드 확인이 메서드에 적용됩니다. 가장 적용 가능한 메서드가 함수인 경우 호출 식의 결과는 함수의 반환 형식으로 형식화된 값으로 분류됩니다. 가장 적용 가능한 메서드가 서브루틴인 경우 결과는 void로 분류됩니다. 가장 적용 가능한 메서드가 본문이 없는 부분 메서드인 경우 호출 식이 무시되고 결과가 void로 분류됩니다.

초기 바인딩된 호출 식의 경우 인수는 대상 메서드에서 해당 매개 변수가 선언되는 순서대로 계산됩니다. 런타임에 바인딩된 멤버 액세스 식의 경우 멤버 액세스 식에 나타나는 순서대로 평가됩니다. 섹션 Late-Bound 식을 참조하세요.

오버로드된 메서드 확인:

오버로드 확인, 인수 목록이 지정된 멤버/형식의 특이성, 제네릭성, 인수 목록에 적용 가능성, 인수 전달 및 선택적 매개 변수, 조건부 메서드 및 형식 인수 유추에 대한 인수 선택: 섹션 오버로드 확인을 참조하세요.

인덱스 식

인덱스 식은 배열 요소를 생성하거나 속성 그룹을 속성 액세스로 다시 분류합니다. 인덱스 식은 순서대로 식, 여는 괄호, 인덱스 인수 목록 및 닫는 괄호로 구성됩니다.

IndexExpression
    : Expression OpenParenthesis ArgumentList? CloseParenthesis
    ;

인덱스 식의 대상은 속성 그룹 또는 값으로 분류되어야 합니다. 인덱스 식은 다음과 같이 처리됩니다.

  • 대상 식이 값으로 분류되고 해당 형식이 배열 형식ObjectSystem.Array이 아니면 형식에 기본 속성이 있어야 합니다. 인덱스는 형식의 모든 기본 속성을 나타내는 속성 그룹에서 수행됩니다. Visual Basic에서 매개 변수가 없는 기본 속성을 선언하는 것은 유효하지 않지만 다른 언어에서는 이러한 속성을 선언할 수 있습니다. 따라서 인수 없이 속성을 인덱싱할 수 있습니다.

  • 식에서 배열 형식의 값이 발생하는 경우 인수 목록의 인수 수는 배열 형식의 순위와 동일해야 하며 명명된 인수를 포함하지 않을 수 있습니다. 런타임에 잘못된 인덱스가 있으면 예외가 System.IndexOutOfRangeException throw됩니다. 각 식은 암시적으로 형식 Integer으로 변환할 수 있어야 합니다. 인덱스 식의 결과는 지정된 인덱스의 변수이며 변수로 분류됩니다.

  • 식이 속성 그룹으로 분류되는 경우 오버로드 확인은 속성 중 하나가 인덱스 인수 목록에 적용 가능한지 여부를 확인하는 데 사용됩니다. 속성 그룹에 접근자가 있는 Get 속성이 하나만 있고 해당 접근자가 인수를 사용하지 않는 경우 속성 그룹은 빈 인수 목록이 있는 인덱스 식으로 해석됩니다. 결과는 현재 인덱스 식의 대상으로 사용됩니다. 적용할 수 있는 속성이 없으면 컴파일 시간 오류가 발생합니다. 그렇지 않으면 식이 속성 그룹의 연결된 대상 식(있는 경우)을 사용하여 속성 액세스가 발생합니다.

  • 식이 런타임에 바인딩된 속성 그룹 또는 형식 ObjectSystem.Array이 있는 값으로 분류되는 경우 인덱스 식 처리는 런타임까지 지연되고 인덱싱은 런타임에 바인딩됩니다. 식은 런타임에 바인딩된 속성 액세스를 다음과 같이 Object입력합니다. 연결된 대상 식은 대상 식(값인 경우) 또는 속성 그룹의 연결된 대상 식입니다. 런타임에 식은 다음과 같이 처리됩니다.

  • 식이 런타임에 바인딩된 속성 그룹으로 분류되면 메서드 그룹, 속성 그룹 또는 값(멤버가 인스턴스 또는 공유 변수인 경우)이 발생할 수 있습니다. 결과가 메서드 그룹 또는 속성 그룹인 경우 인수 목록에 대한 올바른 메서드를 결정하기 위해 오버로드 확인이 그룹에 적용됩니다. 오버로드 확인이 실패하면 예외가 System.Reflection.AmbiguousMatchException throw됩니다. 그런 다음 결과는 속성 액세스 또는 호출로 처리되고 결과가 반환됩니다. 호출이 서브루틴인 경우 결과는 .입니다 Nothing.

  • 대상 식의 런타임 형식이 배열 형식이거나 System.Array인덱스 식의 결과는 지정된 인덱스의 변수 값입니다.

  • 그렇지 않으면 식의 런타임 형식에 기본 속성이 있어야 하며 인덱스는 형식의 모든 기본 속성을 나타내는 속성 그룹에서 수행됩니다. 형식에 기본 속성이 없으면 예외가 System.MissingMemberException throw됩니다.

새 식

New 연산자는 형식의 새 인스턴스를 만드는 데 사용됩니다. 다음과 같은 네 가지 형식의 New 식이 있습니다.

  • 개체 만들기 식은 클래스 형식 및 값 형식의 새 인스턴스를 만드는 데 사용됩니다.

  • 배열 생성 식은 배열 형식의 새 인스턴스를 만드는 데 사용됩니다.

  • 대리자 생성 식(개체 만들기 식의 고유 구문이 없음)은 대리자 형식의 새 인스턴스를 만드는 데 사용됩니다.

  • 익명 개체 만들기 식은 익명 클래스 형식의 새 인스턴스를 만드는 데 사용됩니다.

NewExpression
    : ObjectCreationExpression
    | ArrayExpression
    | AnonymousObjectCreationExpression
    ;

New 식은 값으로 분류되고 결과는 형식의 새 인스턴스입니다.

Object-Creation 식

개체 만들기 식은 클래스 형식 또는 구조체 형식의 새 인스턴스를 만드는 데 사용됩니다.

ObjectCreationExpression
    : 'New' NonArrayTypeName ( OpenParenthesis ArgumentList? CloseParenthesis )?
      ObjectCreationExpressionInitializer?
    ;

ObjectCreationExpressionInitializer
    : ObjectMemberInitializer
    | ObjectCollectionInitializer
    ;

ObjectMemberInitializer
    : 'With' OpenCurlyBrace FieldInitializerList CloseCurlyBrace
    ;

FieldInitializerList
    : FieldInitializer ( Comma FieldInitializer )*
    ;

FieldInitializer
    : 'Key'? ('.' IdentifierOrKeyword Equals )? Expression
    ;

ObjectCollectionInitializer
    : 'From' CollectionInitializer
    ;

CollectionInitializer
    : OpenCurlyBrace CollectionElementList? CloseCurlyBrace
    ;

CollectionElementList
    : CollectionElement ( Comma CollectionElement )*
    ;

CollectionElement
    : Expression
    | CollectionInitializer
    ;

개체 만들기 식의 형식은 클래스 형식, 구조체 형식 또는 제약 조건이 있는 New 형식 매개 변수여야 하며 클래스가 MustInherit 될 수 없습니다. 클래스 형식 또는 구조체 형식이고 A 선택적 인수 목록인 폼 New T(A)T 의 개체 생성 식이 있는 경우 오버로드 확인은 호출할 올바른 생성자를 T 결정합니다. 제약 조건이 있는 New 형식 매개 변수에는 매개 변수가 없는 단일 생성자가 있는 것으로 간주됩니다. 호출할 수 있는 생성자가 없으면 컴파일 시간 오류가 발생합니다. 그렇지 않으면 식에서 선택한 생성자를 사용하는 새 인스턴스 T 를 만듭니다. 인수가 없으면 괄호를 생략할 수 있습니다.

인스턴스가 할당되는 위치는 인스턴스가 클래스 형식인지 값 형식인지에 따라 달라집니다. New 클래스 형식의 인스턴스는 시스템 힙에 생성되고, 값 형식의 새 인스턴스는 스택에 직접 만들어집니다.

개체 생성 식은 선택적으로 생성자 인수 뒤의 멤버 이니셜라이저 목록을 지정할 수 있습니다. 이러한 멤버 이니셜라이저에는 키워드 With접두사로 지정되며 이니셜라이저 목록은 문 컨텍스트 With 에 있는 것처럼 해석됩니다. 예를 들어 클래스를 지정합니다.

Class Customer
    Dim Name As String
    Dim Address As String
End Class

코드:

Module Test
    Sub Main()
        Dim x As New Customer() With { .Name = "Bob Smith", _
            .Address = "123 Main St." }
    End Sub
End Module

대략 다음과 같습니다.

Module Test
    Sub Main()
        Dim x, _t1 As Customer

        _t1 = New Customer()
        With _t1
            .Name = "Bob Smith"
            .Address = "123 Main St."
        End With

        x = _t1
    End Sub
End Module

각 이니셜라이저는 할당할 이름을 지정해야 하며, 이름은 생성되는 형식의 인스턴스ReadOnly 가 아닌 변수 또는 속성이어야 합니다. 생성 Object되는 형식이 있으면 멤버 액세스가 늦게 바인딩되지 않습니다. 이니셜라이저는 키워드를 Key 사용할 수 없습니다. 형식의 각 멤버는 한 번만 초기화할 수 있습니다. 그러나 이니셜라이저 식은 서로를 참조할 수 있습니다. 다음은 그 예입니다.

Module Test
    Sub Main()
        Dim x As New Customer() With { .Name = "Bob Smith", _
            .Address = .Name & " St." }
    End Sub
End Module

이니셜라이저는 왼쪽에서 오른쪽으로 할당되므로 이니셜라이저가 아직 초기화되지 않은 멤버를 참조하는 경우 생성자가 실행된 후 인스턴스 변수 값이 표시됩니다.

Module Test
    Sub Main()
        ' The value of Address will be " St." since Name has not been
        ' assigned yet.
        Dim x As New Customer() With { .Address = .Name & " St." }
    End Sub
End Module

이니셜라이저는 중첩될 수 있습니다.

Class Customer
    Dim Name As String
    Dim Address As Address
    Dim Age As Integer
End Class

Class Address
    Dim Street As String
    Dim City As String
    Dim State As String
    Dim ZIP As String
End Class

Module Test
    Sub Main()
        Dim c As New Customer() With { _
            .Name = "John Smith", _
            .Address = New Address() With { _
                .Street = "23 Main St.", _
                .City = "Peoria", _
                .State = "IL", _
                .ZIP = "13934" }, _
            .Age = 34 }
    End Sub
End Module

생성되는 형식이 컬렉션 형식이고 명명 Add 된 인스턴스 메서드(확장 메서드 및 공유 메서드 포함)가 있는 경우 개체 만들기 식은 키워드 From에 접두사로 붙은 컬렉션 이니셜라이저를 지정할 수 있습니다. 개체 생성 식은 멤버 이니셜라이저와 컬렉션 이니셜라이저를 둘 다 지정할 수 없습니다. 컬렉션 이니셜라이저의 각 요소는 함수 호출 Add 에 대한 인수로 전달됩니다. 다음은 그 예입니다.

Dim list = New List(Of Integer)() From { 1, 2, 3, 4 }

다음과 동일합니다.

Dim list = New List(Of Integer)()
list.Add(1)
list.Add(2)
list.Add(3)

요소가 컬렉션 이니셜라이저 자체인 경우 하위 컬렉션 이니셜라이저의 각 요소는 함수에 개별 인수 Add 로 전달됩니다. 예를 들어 다음을 수행합니다.

Dim dict = Dictionary(Of Integer, String) From { { 1, "One" },{ 2, "Two" } }

다음과 동일합니다.

Dim dict = New Dictionary(Of Integer, String)
dict.Add(1, "One")
dict.Add(2, "Two")

이 확장은 항상 수행되며 한 수준 깊이에서만 수행됩니다. 그 후 하위 이니셜라이저는 배열 리터럴로 간주됩니다. 다음은 그 예입니다.

' Error: List(Of T) does not have an Add method that takes two parameters.
Dim list = New List(Of Integer())() From { { 1, 2 }, { 3, 4 } }

' OK, this initializes the dictionary with (Integer, Integer()) pairs.
Dim dict = New Dictionary(Of Integer, Integer())() From _
        { {  1, { 2, 3 } }, { 3, { 4, 5 } } }

배열 식

배열 식은 배열 형식의 새 인스턴스를 만드는 데 사용됩니다. 배열 식에는 배열 만들기 식과 배열 리터럴의 두 가지 유형이 있습니다.

배열 만들기 식

배열 크기 초기화 한정자가 제공된 경우 결과 배열 형식은 배열 크기 초기화 인수 목록에서 각 개별 인수를 삭제하여 파생됩니다. 각 인수의 값은 새로 할당된 배열 인스턴스에서 해당 차원의 상한을 결정합니다. 식에 비어 있는 컬렉션 이니셜라이저가 없는 경우 인수 목록의 각 인수는 상수여야 하며 식 목록에서 지정한 순위 및 차원 길이는 컬렉션 이니셜라이저의 인수와 일치해야 합니다.

Dim a() As Integer = New Integer(2) {}
Dim b() As Integer = New Integer(2) { 1, 2, 3 }
Dim c(,) As Integer = New Integer(1, 2) { { 1, 2, 3 } , { 4, 5, 6 } }

' Error, length/initializer mismatch.
Dim d() As Integer = New Integer(2) { 0, 1, 2, 3 }

배열 크기 초기화 한정자가 제공되지 않은 경우 형식 이름은 배열 형식이어야 하며 컬렉션 이니셜라이저는 비어 있거나 지정된 배열 형식의 순위와 동일한 수의 중첩 수준을 가져야 합니다. 가장 안쪽 중첩 수준의 모든 요소는 배열의 요소 형식으로 암시적으로 변환할 수 있어야 하며 값으로 분류되어야 합니다. 각 중첩된 컬렉션 이니셜라이저의 요소 수는 항상 동일한 수준에서 다른 컬렉션의 크기와 일치해야 합니다. 개별 차원 길이는 컬렉션 이니셜라이저의 각 해당 중첩 수준에 있는 요소 수에서 유추됩니다. 컬렉션 이니셜라이저가 비어 있으면 각 차원의 길이는 0입니다.

Dim e() As Integer = New Integer() { 1, 2, 3 }
Dim f(,) As Integer = New Integer(,) { { 1, 2, 3 } , { 4, 5, 6 } }

' Error: Inconsistent numbers of elements!
Dim g(,) As Integer = New Integer(,) { { 1, 2 }, { 4, 5, 6 } }

' Error: Inconsistent levels of nesting!
Dim h(,) As Integer = New Integer(,) { 1, 2, { 3, 4 } }

컬렉션 이니셜라이저의 가장 바깥쪽 중첩 수준은 배열의 맨 왼쪽 차원에 해당하며 가장 안쪽 중첩 수준은 가장 오른쪽 차원에 해당합니다. 예:

Dim array As Integer(,) = _
    { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }, { 8, 9 } }

다음과 같습니다.

Dim array(4, 1) As Integer

array(0, 0) = 0: array(0, 1) = 1
array(1, 0) = 2: array(1, 1) = 3
array(2, 0) = 4: array(2, 1) = 5
array(3, 0) = 6: array(3, 1) = 7
array(4, 0) = 8: array(4, 1) = 9

컬렉션 이니셜라이저가 비어 있고(즉, 중괄호가 포함되지만 이니셜라이저 목록이 없는) 초기화되는 배열의 차원 범위가 알려진 경우 빈 컬렉션 이니셜라이저는 모든 요소가 요소 형식의 기본값으로 초기화된 지정된 크기의 배열 인스턴스를 나타냅니다. 초기화되는 배열의 차원 범위를 알 수 없는 경우 빈 컬렉션 이니셜라이저는 모든 차원이 크기가 0인 배열 인스턴스를 나타냅니다.

배열 인스턴스의 순위와 각 차원의 길이는 인스턴스의 전체 수명 동안 상수입니다. 즉, 기존 배열 인스턴스의 순위를 변경할 수 없으며 차원의 크기를 조정할 수도 없습니다.

배열 리터럴

배열 리터럴은 식 컨텍스트와 컬렉션 이니셜라이저의 조합에서 요소 형식, 순위 및 경계가 유추되는 배열을 나타냅니다. 섹션 식 재분류에 설명되어 있습니다.

ArrayExpression
    : ArrayCreationExpression
    | ArrayLiteralExpression
    ;

ArrayCreationExpression
    : 'New' NonArrayTypeName ArrayNameModifier CollectionInitializer
    ;

ArrayLiteralExpression
    : CollectionInitializer
    ;

다음은 그 예입니다.

' array of integers
Dim a = {1, 2, 3}

' array of shorts
Dim b = {1S, 2S, 3S}

' array of shorts whose type is taken from the context
Dim c As Short() = {1, 2, 3}

' array of type Integer(,)
Dim d = {{1, 0}, {0, 1}}

' jagged array of rank ()()
Dim e = {({1, 0}), ({0, 1})}

' error: inconsistent rank
Dim f = {{1}, {2, 3}}

' error: inconsistent rank
Dim g = {1, {2}}

배열 리터럴의 컬렉션 이니셜라이저에 대한 형식 및 요구 사항은 배열 생성 식의 컬렉션 이니셜라이저와 정확히 동일합니다.

메모. 배열 리터럴은 그 자체로 배열을 만들지 않습니다. 대신 배열을 만드는 값으로 식의 재분류입니다. 예를 들어 변환 CType(new Integer() {1,2,3}, Short()) 은 변환할 수 없으므로 변환할 수 없습니다 Integer()Short(). 하지만 CType({1,2,3},Short()) 먼저 배열 리터럴을 배열 생성 식 New Short() {1,2,3}으로 재분류하기 때문에 식이 가능합니다.

Delegate-Creation 식

대리자 생성 식은 대리자 형식의 새 인스턴스를 만드는 데 사용됩니다. 대리자 생성 식의 인수는 메서드 포인터 또는 람다 메서드로 분류된 식이어야 합니다.

인수가 메서드 포인터인 경우 메서드 포인터에서 참조하는 메서드 중 하나를 대리자 형식의 서명에 적용할 수 있어야 합니다. 다음과 같은 경우 대리자 형식 D 에 메서드 M 를 적용할 수 있습니다.

  • M 가 없거나 Partial 본문이 있는 경우

  • D 둘 다 M 함수이거나 D 서브루틴입니다.

  • M 매개 D 변수 수가 같습니다.

  • 각 매개 변수 형식은 M 해당 매개 변수 형식 D의 형식에서 변환되고 해당 한정자(즉 ByRef, 일치 ByVal)가 일치합니다.

  • 의 반환 형식 M(있는 경우)은 반환 형식으로 변환합니다 D.

메서드 포인터가 런타임에 바인딩된 액세스를 참조하는 경우 런타임에 바인딩된 액세스는 대리자 형식과 동일한 수의 매개 변수를 가진 함수로 간주됩니다.

strict 의미 체계를 사용하지 않고 메서드 포인터에서 참조하는 메서드가 하나만 있지만 매개 변수가 없고 대리자 형식이 적용된다는 사실 때문에 적용할 수 없는 경우 메서드는 적용 가능한 것으로 간주되며 매개 변수 또는 반환 값은 무시됩니다. 다음은 그 예입니다.

Delegate Sub F(x As Integer)

Module Test
    Sub M()
    End Sub

    Sub Main()
        ' Valid
        Dim x As F = AddressOf M
    End Sub
End Module

메모. 이 완화는 확장 메서드 때문에 엄격한 의미 체계를 사용하지 않는 경우에만 허용됩니다. 확장 메서드는 일반 메서드를 적용할 수 없는 경우에만 고려되므로 매개 변수가 없는 인스턴스 메서드는 대리자 생성을 위해 매개 변수가 있는 확장 메서드를 숨길 수 있습니다.

메서드 포인터에서 참조하는 메서드를 둘 이상 대리자 형식에 적용할 수 있는 경우 오버로드 확인은 후보 메서드 간에 선택하는 데 사용됩니다. 대리자의 매개 변수 형식은 오버로드 확인을 위해 인수 형식으로 사용됩니다. 가장 적합한 메서드 후보가 없으면 컴파일 시간 오류가 발생합니다. 다음 예제에서는 해당 메서드가 시그니처 및 반환 형식DoubleFunc에 더 적용 가능하기 때문에 두 번째 Square 메서드를 참조하는 대리자를 사용하여 지역 변수를 초기화합니다.

Delegate Function DoubleFunc(x As Double) As Double

Module Test
    Function Square(x As Single) As Single
        Return x * x
    End Function 

    Function Square(x As Double) As Double
        Return x * x
    End Function

    Sub Main()
        Dim a As New DoubleFunc(AddressOf Square)
    End Sub
End Module

두 번째 Square 메서드가 없으면 첫 번째 Square 메서드가 선택되었을 것입니다. 컴파일 환경 또는 Option Strict컴파일 환경에서 엄격한 의미 체계를 지정하는 경우 메서드 포인터에서 참조하는 가장 구체적인 메서드가 대리자 서명보다 좁은 경우 컴파일 시간 오류가 발생합니다. 메서드 M 는 다음과 같은 경우 대리자 형식 D 보다 좁은 것으로 간주됩니다.

  • 매개 변수 형식은 M 해당 매개 변수 형식 D으로 변환됩니다.

  • 또는 반환 형식(있는 경우)에는 반환 형식으로의 M 축소 변환이 있습니다 D.

형식 인수가 메서드 포인터와 연결된 경우 형식 인수 수가 같은 메서드만 고려됩니다. 메서드 포인터와 연결된 형식 인수가 없으면 제네릭 메서드와 시그니처를 일치시키는 경우 형식 유추가 사용됩니다. 다른 일반 형식 유추와 달리 대리자의 반환 형식은 형식 인수를 유추할 때 사용되지만 제네릭 오버로드를 가장 적게 결정할 때는 반환 형식이 고려되지 않습니다. 다음 예제에서는 대리자 생성 식에 형식 인수를 제공하는 두 가지 방법을 보여줍니다.

Delegate Function D(s As String, i As Integer) As Integer
Delegate Function E() As Integer

Module Test
    Public Function F(Of T)(s As String, t1 As T) As T
    End Function

    Public Function G(Of T)() As T
    End Function

    Sub Main()
        Dim d1 As D = AddressOf f(Of Integer)    ' OK, type arg explicit
        Dim d2 As D = AddressOf f                ' OK, type arg inferred

        Dim e1 As E = AddressOf g(Of Integer)    ' OK, type arg explicit
        Dim e2 As E = AddressOf g                ' OK, infer from return
  End Sub
End Module

위의 예제에서 제네릭이 아닌 대리자 형식은 제네릭 메서드를 사용하여 인스턴스화되었습니다. 제네릭 메서드를 사용하여 생성된 대리자 형식의 인스턴스를 만들 수도 있습니다. 다음은 그 예입니다.

Delegate Function Predicate(Of U)(u1 As U, u2 As U) As Boolean

Module Test
    Function Compare(Of T)(t1 As List(of T), t2 As List(of T)) As Boolean
        ...
    End Function

    Sub Main()
        Dim p As Predicate(Of List(Of Integer))
        p = AddressOf Compare(Of Integer)
    End Sub
End Module

대리자 생성 식에 대한 인수가 람다 메서드인 경우 대리자 형식의 서명에 람다 메서드를 적용할 수 있어야 합니다. 다음과 같은 경우 대리자 형식 D 에 람다 메서드 L 를 적용할 수 있습니다.

  • 매개 변수가 있는 경우 L 매개 변수 D 수가 동일합니다. 매개 변수가 없으면 L 매개 변수 D 가 무시됩니다.

  • 각 매개 변수 형식 L 은 해당 매개 변수 형식 D의 형식으로 변환되고 해당 한정자(즉 ByRef, 일치 ByVal)가 일치합니다.

  • 함수인 경우 D 반환 형식은 L 반환 형식으로 변환됩니다 D. (서브루틴인 경우 D 반환 값 L 은 무시됩니다.)

매개 변수의 L 매개 변수 형식을 생략하면 해당 매개 변수의 형식이 유추됩니다. 매개 변수 DL 배열 또는 nullable 이름 한정자가 있으면 컴파일 시간 오류가 발생합니다. 모든 매개 변수 형식 L 을 사용할 수 있게 되면 람다 메서드의 식 형식이 유추됩니다. 다음은 그 예입니다.

Delegate Function F(x As Integer, y As Long) As Long

Module Test
    Sub Main()
        ' b inferred to Integer, c and return type inferred to Long
        Dim a As F = Function(b, c) b + c

        ' e and return type inferred to Integer, f inferred to Long
        Dim d As F = Function(e, f) e + CInt(f)
    End Sub
End Module

대리자 서명이 람다 메서드 또는 메서드 서명과 정확히 일치하지 않는 경우 .NET Framework는 대리자 생성을 기본적으로 지원하지 않을 수 있습니다. 이 경우 람다 메서드 식은 두 메서드를 일치시키는 데 사용됩니다. 다음은 그 예입니다.

Delegate Function IntFunc(x As Integer) As Integer

Module Test
    Function SquareString(x As String) As String
        Return CInt(x) * CInt(x)
    End Function 

    Sub Main()
        ' The following two lines are equivalent
        Dim a As New IntFunc(AddressOf SquareString)
        Dim b As New IntFunc( _
            Function(x As Integer) CInt(SquareString(CStr(x))))
    End Sub
End Module

대리자 생성 식의 결과는 메서드 포인터 식에서 연결된 대상 식(있는 경우)과 일치하는 메서드를 참조하는 대리자 인스턴스입니다. 대상 식이 값 형식으로 입력된 경우 대리자는 힙에 있는 개체의 메서드만 가리킬 수 있으므로 값 형식이 시스템 힙에 복사됩니다. 대리자가 참조하는 메서드와 개체는 대리자의 전체 수명 동안 상수로 유지됩니다. 즉, 대리자를 만든 후에는 대리자의 대상이나 개체를 변경할 수 없습니다.

익명 Object-Creation 식

멤버 이니셜라이저가 있는 개체 만들기 식은 형식 이름을 완전히 생략할 수도 있습니다.

AnonymousObjectCreationExpression
    : 'New' ObjectMemberInitializer
    ;

이 경우 익명 형식은 식의 일부로 초기화된 멤버의 형식과 이름을 기반으로 생성됩니다. 다음은 그 예입니다.

Module Test
    Sub Main()
        Dim Customer = New With { .Name = "John Smith", .Age = 34 }

        Console.WriteLine(Customer.Name)
    End Sub
End Module

익명 개체 만들기 식에서 만든 형식은 이름이 없고, 직접 Object상속되며, 멤버 이니셜라이저 목록에 할당된 멤버와 이름이 같은 속성 집합이 있는 클래스입니다. 각 속성의 형식은 지역 변수 형식 유추와 동일한 규칙을 사용하여 유추됩니다. 생성된 익명 형식도 재정 ToString의하여 모든 멤버와 해당 값의 문자열 표현을 반환합니다. (이 문자열의 정확한 형식은 이 사양의 범위를 벗어)

기본적으로 익명 형식에서 생성된 속성은 읽기/쓰기가 가능합니다. 한정자를 사용하여 익명 형식 속성을 읽기 전용으로 표시할 Key 수 있습니다. 한 Key 정자는 필드를 사용하여 무명 형식이 나타내는 값을 고유하게 식별할 수 있도록 지정합니다. 속성을 읽기 전용으로 만드는 것 외에도 익명 형식을 재정 Equals 의하고 GetHashCode 인터페이스 System.IEquatable(Of T) 를 구현합니다(익명 형식 T을 입력). 멤버는 다음과 같이 정의됩니다.

Function Equals(obj As Object) As BooleanFunction Equals(val As T) As Boolean 인스턴스가 동일한 형식의지 확인하고 .를 사용하여 Object.EqualsKey 멤버를 비교하여 구현됩니다. 모든 Key 멤버가 같으면 반환True되고, Equals 그렇지 않으면 Equals 반환됩니다False.

Function GetHashCode() As Integer는 익명 형식 GetHashCode 의 두 인스턴스에 대해 true인 경우 Equals 동일한 값을 반환할 수 있도록 구현됩니다. 해시는 시드 값으로 시작한 다음 각 Key 멤버에 대해 해시를 31로 곱하고 멤버가 참조 형식이 아니거나 nullable 값 형식Nothing이 아닌 경우 멤버의 해시 값(제공)GetHashCode을 추가 Key 합니다.

예를 들어 문에서 만든 형식은 다음과 같습니다.

Dim zipState = New With { Key .ZipCode = 98112, .State = "WA" }

는 다음과 비슷한 클래스를 만듭니다(정확한 구현은 다를 수 있음).

Friend NotInheritable Class $Anonymous1
    Implements IEquatable(Of $Anonymous1)

    Private ReadOnly _zipCode As Integer
    Private _state As String

    Public Sub New(zipCode As Integer, state As String)
        _zipCode = zipcode
        _state = state
    End Sub

    Public ReadOnly Property ZipCode As Integer
        Get
            Return _zipCode
        End Get
    End Property

    Public Property State As String
        Get
            Return _state
        End Get
        Set (value As Integer)
            _state = value
        End Set
    End Property

    Public Overrides Function Equals(obj As Object) As Boolean
        Dim val As $Anonymous1 = TryCast(obj, $Anonymous1)
        Return Equals(val)
    End Function

    Public Overloads Function Equals(val As $Anonymous1) As Boolean _
        Implements IEquatable(Of $Anonymous1).Equals

        If val Is Nothing Then 
            Return False
        End If

        If Not Object.Equals(_zipCode, val._zipCode) Then 
            Return False
        End If

        Return True
    End Function

    Public Overrides Function GetHashCode() As Integer
        Dim hash As Integer = 0

        hash = hash Xor _zipCode.GetHashCode()

        Return hash
    End Function

    Public Overrides Function ToString() As String
        Return "{ Key .ZipCode = " & _zipCode & ", .State = " & _state & " }"
    End Function
End Class

다른 형식의 필드에서 익명 형식이 만들어지는 상황을 간소화하기 위해 다음 경우 식에서 직접 필드 이름을 유추할 수 있습니다.

  • 간단한 이름 식 x 은 이름을 x유추합니다.

  • 멤버 액세스 식 x.y 은 이름을 y유추합니다.

  • 사전 조회 식 x!y 은 이름을 y유추합니다.

  • 인수 x() 가 없는 호출 또는 인덱스 식은 이름을 x유추합니다.

  • XML 멤버 액세스 식x.<y>x...<y>x.@y 이름을 y유추합니다.

  • 멤버 액세스 식의 대상인 XML 멤버 액세스 식 x.<y>.z 은 이름을 z유추합니다.

  • 인수 x.<y>.z() 가 없는 호출 또는 인덱스 식의 대상인 XML 멤버 액세스 식은 이름을 z유추합니다.

  • 호출 또는 인덱스 식의 대상인 XML 멤버 액세스 식 x.<y>(0) 은 이름을 y유추합니다.

이니셜라이저는 유추된 이름에 대한 식의 할당으로 해석됩니다. 예를 들어 다음 이니셜라이저는 동일합니다.

Class Address
    Public Street As String
    Public City As String
    Public State As String
    Public ZIP As String
End Class

Class C1
    Sub Test(a As Address)
        Dim cityState1 = New With { .City = a.City, .State = a.State }
        Dim cityState2 = New With { a.City, a.State }
    End Sub
End Class

형식의 기존 멤버와 충돌하는 GetHashCode멤버 이름을 유추하면 컴파일 시간 오류가 발생합니다. 일반 멤버 이니셜라이저와 달리 익명 개체 만들기 식은 멤버 이니셜라이저가 순환 참조를 가지거나 초기화되기 전에 멤버를 참조하는 것을 허용하지 않습니다. 다음은 그 예입니다.

Module Test
    Sub Main()
        ' Error: Circular references
        Dim x = New With { .a = .b, .b = .a }

        ' Error: Referring to .b before it has been assigned to
        Dim y = New With { .a = .b, .b = 10 }

        ' Error: Referring to .a before it has been assigned to
        Dim z = New With { .a = .a }
    End Sub
End Module

두 개의 익명 클래스 생성 식이 동일한 메서드 내에서 발생하고 동일한 결과 셰이프를 생성하는 경우(속성 순서, 속성 이름 및 속성 형식이 모두 일치하는 경우) 둘 다 동일한 익명 클래스를 참조합니다. 이니셜라이저를 사용하는 인스턴스 또는 공유 멤버 변수의 메서드 범위는 변수가 초기화되는 생성자입니다.

메모. 컴파일러가 어셈블리 수준과 같이 익명 형식을 추가로 통합하도록 선택할 수 있지만 지금은 이를 사용할 수 없습니다.

캐스트 식

캐스트 식은 식을 지정된 형식으로 강제 변환합니다. 특정 캐스트 키워드는 식을 기본 형식으로 강제 변환합니다. 세 개의 CTypeTryCast 일반 캐스트 키워드 및 DirectCast식을 형식으로 강제 변환합니다.

CastExpression
    : 'DirectCast' OpenParenthesis Expression Comma TypeName CloseParenthesis
    | 'TryCast' OpenParenthesis Expression Comma TypeName CloseParenthesis
    | 'CType' OpenParenthesis Expression Comma TypeName CloseParenthesis
    | CastTarget OpenParenthesis Expression CloseParenthesis
    ;

CastTarget
    : 'CBool' | 'CByte' | 'CChar'  | 'CDate'  | 'CDec' | 'CDbl' | 'CInt'
    | 'CLng'  | 'CObj'  | 'CSByte' | 'CShort' | 'CSng' | 'CStr' | 'CUInt'
    | 'CULng' | 'CUShort'
    ;

DirectCastTryCast 특별한 동작이 있습니다. 이 때문에 네이티브 변환만 지원합니다. 또한 식의 대상 형식은 TryCast 값 형식일 수 없습니다. 사용자 정의 변환 연산자는 사용되거나 사용될 때 DirectCastTryCast 고려되지 않습니다. (참고. 변환 집합과 TryCast 지원은 "네이 DirectCast 티브 CLR" 변환을 구현하기 때문에 제한됩니다. 목적은 DirectCast "unbox" 명령의 기능을 제공하는 반면, 목적은 TryCast "isinst" 명령의 기능을 제공하는 것입니다. CLR 지침에 매핑되므로 CLR에서 직접 지원하지 않는 변환을 지원하면 의도한 목적에 어지럽습니다.)

DirectCast 는 .와 다르게 형식화된 Object 식을 변환합니다 CType. 런타임 형식이 기본 값 형식 DirectCast 인 형식 Object 의 식을 변환할 때 지정된 형식이 식의 런타임 형식과 System.NullReferenceException 같지 않거나 식이 계산되는 경우 예외를 throw System.InvalidCastException 합니다Nothing. (참고. 위에서 설명한 것처럼 식 DirectCast 의 형식이면 CLR 명령 "unbox"에 직접 매핑됩니다Object. 반면, CType 기본 형식 간의 변환을 지원하도록 변환을 수행하는 런타임 도우미에 대한 호출로 바뀝니다. 식이 기본 값 형식으로 변환되고 실제 인스턴스의 형식이 대상 형식 DirectCast 과 일치하는 경우 Object .)보다 CType훨씬 빠릅니다.

TryCast 식을 변환하지만 식을 대상 형식으로 변환할 수 없는 경우 예외를 throw하지 않습니다. 대신 런 TryCast 타임에 Nothing 식을 변환할 수 없는 경우 발생합니다. (참고. 위에서 TryCast 설명한 대로 CLR 명령 "isinst"에 직접 매핑됩니다. 형식 검사와 변환을 단일 작업 TryCastTypeOf ... IsCType으로 결합하면 .)

다음은 그 예입니다.

Interface ITest
    Sub Test()
End Interface

Module Test
    Sub Convert(o As Object)
        Dim i As ITest = TryCast(o, ITest)

        If i IsNot Nothing Then
            i.Test()
        End If
    End Sub
End Module

식 형식에서 지정된 형식으로의 변환이 없으면 컴파일 시간 오류가 발생합니다. 그렇지 않으면 식이 값으로 분류되고 결과는 변환에 의해 생성된 값입니다.

연산자 식

연산자의 종류는 두 가지가 있습니다. 단항 연산자는 하나의 피연산자를 사용하고 접두사 표기법(예: -x)을 사용합니다. 이진 연산 자는 두 개의 피연산자를 사용하고 접두사 표기법(예: x + y)을 사용합니다. 항상 발생하는 관계형 연산자를 제외하고 특정 형식에 Boolean대해 정의된 연산자는 해당 형식을 생성합니다. 연산자에 대한 피연산자는 항상 값으로 분류되어야 합니다. 연산자 식의 결과는 값으로 분류됩니다.

OperatorExpression
    : ArithmeticOperatorExpression
    | RelationalOperatorExpression
    | LikeOperatorExpression
    | ConcatenationOperatorExpression
    | ShortCircuitLogicalOperatorExpression
    | LogicalOperatorExpression
    | ShiftOperatorExpression
    | AwaitOperatorExpression
    ;

연산자 우선 순위 및 결합성

식에 여러 이진 연산자가 포함된 경우 연산자의 우선 순위 는 개별 이진 연산자가 평가되는 순서를 제어합니다. 예를 들어 연산자가 연산자보다 우선 순위가 * 높기 때문에 식 x + y * z+ 계산 x + (y * z) 됩니다. 다음 표에서는 이진 연산자를 우선 순위의 내림차순으로 나열합니다.

범주 연산자
기본 모든 비 연산자 식
기다리다 Await
지수화 ^
단항 부정 +, -
곱셈 *, /
정수 나누기 \
계수 Mod
첨가물 +, -
연결하기 &
변화 <<, >>
관계형 =,<>, <, >, <=, >=Like, IsIsNot
논리 부정 Not
논리적 AND And, AndAlso
논리적 또는 Or, OrElse
논리 XOR Xor

식에 동일한 우선 순위를 가진 두 개의 연산자가 포함된 경우 연산자의 결합성은 연산이 수행되는 순서를 제어합니다. 모든 이진 연산자는 왼쪽에서 오른쪽으로 연산이 수행된다는 의미의 왼쪽 연결 연산자입니다. 우선 순위 및 결합성은 괄호 식을 사용하여 제어할 수 있습니다.

개체 피연산자

각 연산자가 지원하는 일반 형식 외에도 모든 연산자는 형식 Object의 피연산자를 지원합니다. 피연산자에 Object 적용된 연산자는 값에 대한 Object 메서드 호출과 유사하게 처리됩니다. 런타임에 바인딩된 메서드 호출을 선택할 수 있습니다. 이 경우 컴파일 시간 형식이 아닌 피연산자의 런타임 형식이 작업의 유효성과 형식을 결정합니다. strict 의미 체계가 컴파일 환경 또는 형식에 의해 Option Strict지정된 경우 형식 Object 피연산자가 있는 모든 연산자는 및 IsIsNot 연산자를 제외한 TypeOf...Is컴파일 시간 오류를 발생합니다.

연산자 확인에서 연산을 런타임에 바인딩해야 한다고 결정하면 연산자의 런타임 형식이 연산자가 지원하는 형식인 경우 연산자가 피연산자 형식에 연산자를 적용한 결과입니다. 이 값 Nothing 은 이진 연산자 식에서 다른 피연산자 형식의 기본값으로 처리됩니다. 단항 연산자 식에서 또는 두 피연산자가 이진 연산자 식에 있는 Nothing 경우 연산자의 형식은 연산자의 유일한 결과 형식이거나 Integer 연산자의 결과 Integer형식입니다. 작업의 결과는 항상 다시 캐스팅됩니다 Object. 피연산자 형식에 유효한 연산자가 없으면 예외가 System.InvalidCastException throw됩니다. 런타임 시 변환은 암시적 또는 명시적 여부에 관계없이 수행됩니다.

숫자 이진 작업의 결과로 오버플로 예외가 발생하는 경우(정수 오버플로 검사가 설정 또는 해제되었는지 여부에 관계 없이) 결과 형식은 가능한 경우 다음 더 넓은 숫자 형식으로 승격됩니다. 예를 들어 다음 코드를 고려합니다.

Module Test
    Sub Main()
        Dim o As Object = CObj(CByte(2)) * CObj(CByte(255))

        Console.WriteLine(o.GetType().ToString() & " = " & o)
    End Sub
End Module

다음 결과를 출력합니다.

System.Int16 = 512

숫자를 저장할 수 있는 더 넓은 숫자 형식이 없으면 예외가 System.OverflowException throw됩니다.

연산자 확인

연산자 형식과 피연산자 집합이 지정된 경우 연산자 확인은 피연산자에 사용할 연산자를 결정합니다. 연산자를 확인할 때 다음 단계를 사용하여 먼저 사용자 정의 연산자를 고려합니다.

  1. 먼저 모든 후보 연산자가 수집됩니다. 후보 연산자는 원본 형식에 있는 특정 연산자 형식의 모든 사용자 정의 연산자이며 대상 형식의 특정 형식에 대한 모든 사용자 정의 연산자입니다. 원본 형식과 대상 형식이 관련된 경우 공통 연산자는 한 번만 고려됩니다.

  2. 그런 다음 오버로드 확인이 연산자와 피연산자에 적용되어 가장 구체적인 연산자를 선택합니다. 이진 연산자의 경우 이로 인해 런타임에 바인딩된 호출이 발생할 수 있습니다.

형식에 대한 후보 연산자를 수집할 때 형식 T?T 연산자가 대신 사용됩니다. Tnullable이 아닌 값 형식만 포함하는 사용자 정의 연산자도 모두 해제됩니다. 리프트된 연산자는 반환 형식과 IsFalse 반환 형식(반드시Boolean)을 제외하고 모든 값 형식의 IsTrue nullable 버전을 사용합니다. 해제된 연산자는 피연산자를 nullable이 아닌 버전으로 변환한 다음 사용자 정의 연산자를 평가한 다음 결과 형식을 nullable 버전으로 변환하여 평가됩니다. ether 피연산자인 Nothing경우 식의 결과는 결과 형식의 Nothing nullable 버전으로 형식화된 값입니다. 다음은 그 예입니다.

Structure T
    ...
End Structure

Structure S
    Public Shared Operator +(ByVal op1 As S, ByVal op2 As T) As T
        ...
    End Operator
End Structure

Module Test
    Sub Main()
        Dim x As S?
        Dim y, z As T?

        ' Valid, as S + T = T is lifted to S? + T? = T?
        z = x + y 
    End Sub
End Module

연산자가 이진 연산자이고 피연산자 중 하나가 참조 형식인 경우 연산자도 해제되지만 연산자에 대한 바인딩은 오류를 생성합니다. 다음은 그 예입니다.

Structure S1
    Public F1 As Integer

    Public Shared Operator +(left As S1, right As String) As S1
       ...
    End Operator
End Structure

Module Test
    Sub Main()
        Dim a? As S1
        Dim s As String
        
        ' Error: '+' is not defined for S1? and String
        a = a + s
    End Sub
End Module

메모. 이 규칙은 이후 버전에서 null 전파 참조 형식을 추가할지 여부를 고려했기 때문에 존재합니다. 이 경우 두 형식 간의 이진 연산자의 경우 동작이 변경됩니다.

변환과 마찬가지로 사용자 정의 연산자는 항상 리프트된 연산자보다 선호됩니다.

오버로드된 연산자를 확인할 때 Visual Basic에 정의된 클래스와 다른 언어로 정의된 클래스 간에 차이가 있을 수 있습니다.

  • 다른 언어NotAnd에서는 논리 연산자와 Or 비트 연산자로 오버로드될 수 있습니다. 외부 어셈블리에서 가져오면 두 폼 중 하나가 이러한 연산자를 위한 유효한 오버로드로 허용됩니다. 그러나 논리 연산자와 비트 연산자를 모두 정의하는 형식의 경우 비트 구현만 고려됩니다.

  • 다른 언어에서는 >> 서명된 연산자와 << 서명되지 않은 연산자로 오버로드될 수 있습니다. 외부 어셈블리에서 가져오면 두 폼 중 하나가 유효한 오버로드로 허용됩니다. 그러나 서명된 연산자와 서명되지 않은 연산자를 모두 정의하는 형식의 경우 서명된 구현만 고려됩니다.

  • 피연산자에 가장 구체적인 사용자 정의 연산자가 없는 경우 내장 연산자가 고려됩니다. 피연산자에 대해 정의된 내장 연산자가 없고 피연산자 중 하나에 Object 형식이 있으면 연산자가 런타임에 바인딩된 것으로 확인됩니다. 그렇지 않으면 컴파일 시간 오류 결과가 발생합니다.

이전 버전의 Visual Basic에서는 정확히 하나의 개체 형식 피연산자가 있고 적용 가능한 사용자 정의 연산자가 없고 적용 가능한 내장 연산자가 없는 경우 오류가 발생했습니다. 이제 Visual Basic 11부터 런타임에 바인딩된 것으로 확인됩니다. 다음은 그 예입니다.

Module Module1
  Sub Main()
      Dim p As Object = Nothing
      Dim U As New Uri("http://www.microsoft.com")
      Dim j = U * p  ' is now resolved late-bound
   End Sub
End Module

내장 연산자가 있는 형식 T 은 동일한 연산 T?자도 정의합니다. 연산 T?T자의 결과는 피연산자 Nothing중 하나가면 연산 Nothing 자의 결과가 됩니다(즉, null 값이 전파됨)는 제외됩니다. 작업의 형식을 확인하기 위해 연산 ? 이 있는 피연산자에서 제거되고, 작업의 형식이 결정되며 ? , 피연산자 중 nullable 값 형식인 경우 연산 형식에 추가됩니다. 다음은 그 예입니다.

Dim v1? As Integer = 10
Dim v2 As Long = 20

' Type of operation will be Long?
Console.WriteLine(v1 + v2)

각 연산자는 정의된 내장 형식과 피연산자 형식에 따라 수행되는 작업의 형식을 나열합니다. 내장 연산 형식의 결과는 다음과 같은 일반적인 규칙을 따릅니다.

  • 모든 피연산자가 동일한 형식이고 형식에 대해 연산자가 정의된 경우 변환이 발생하지 않고 해당 형식의 연산자가 사용됩니다.

  • 연산자에 대해 형식이 정의되지 않은 피연산자는 다음 단계를 사용하여 변환되고 연산자는 새 형식에 대해 확인됩니다.

    • 피연산자는 연산자와 피연산자 모두에 대해 정의되고 암시적으로 변환할 수 있는 다음으로 넓은 형식으로 변환됩니다.

    • 이러한 형식이 없으면 피연산자는 연산자와 피연산자 모두에 대해 정의되고 암시적으로 변환할 수 있는 가장 좁은 형식으로 변환됩니다.

    • 이러한 형식이 없거나 변환이 발생할 수 없는 경우 컴파일 시간 오류가 발생합니다.

  • 그렇지 않으면 피연산자가 더 넓은 피연산자 형식으로 변환되고 해당 형식의 연산자가 사용됩니다. 더 좁은 피연산자 형식을 더 넓은 연산자 형식으로 암시적으로 변환할 수 없는 경우 컴파일 시간 오류가 발생합니다.

그러나 이러한 일반적인 규칙에도 불구하고 연산자 결과 테이블에는 여러 특수 사례가 호출됩니다.

메모. 서식을 지정하기 위해 연산자 형식 테이블은 미리 정의된 이름을 처음 두 문자로 약어로 지정합니다. 따라서 "By"는 Byte"UI" UInteger, "St" 등입니다 String. "Err"은 지정된 피연산자 형식에 대해 정의된 작업이 없음을 의미합니다.

산술 연산자

*,/, \, ^, Mod+- 연산자는 산술 연산자입니다.

ArithmeticOperatorExpression
    : UnaryPlusExpression
    | UnaryMinusExpression
    | AdditionOperatorExpression
    | SubtractionOperatorExpression
    | MultiplicationOperatorExpression
    | DivisionOperatorExpression
    | ModuloOperatorExpression
    | ExponentOperatorExpression
    ;

부동 소수점 산술 연산은 작업의 결과 형식보다 정밀도가 높은 연산을 수행할 수 있습니다. 예를 들어 일부 하드웨어 아키텍처는 형식보다 Double 범위와 정밀도가 큰 "확장" 또는 "long double" 부동 소수점 형식을 지원하며 이 높은 정밀도 형식을 사용하여 모든 부동 소수점 작업을 암시적으로 수행합니다. 하드웨어 아키텍처는 과도한 성능 비용으로만 정밀도가 낮은 부동 소수점 작업을 수행할 수 있습니다. Visual Basic에서는 성능과 정밀도를 모두 몰수하기 위해 구현을 필요로 하는 대신 모든 부동 소수점 작업에 더 높은 정밀도 형식을 사용할 수 있습니다. 보다 정확한 결과를 제공하는 것 외에는 측정 가능한 효과가 거의 없습니다. 그러나 형식 x * y / z의 식에서 곱하기는 범위를 벗어난 Double 결과를 생성하지만 후속 나누기는 임시 결과를 다시 범위로 가져오며, 식이 더 높은 범위 형식으로 Double 평가된다는 사실은 무한대 대신 유한한 결과가 생성될 수 있습니다.

단항 더하기 연산자

UnaryPlusExpression
    : '+' Expression
    ;

단항 더하기 연산자는 , ,SByte, UShort, Short, IntegerUInteger, ULong, SingleLongDoubleDecimal 형식에 대해 Byte정의됩니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
Sh(Sh) SB 곁에 Sh(Sh) 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과

단항 빼기 연산자

UnaryMinusExpression
    : '-' Expression
    ;

단항 빼기 연산자는 다음 형식에 대해 정의됩니다.

SByte, Short, IntegerLong. 결과는 0에서 피연산자를 빼서 계산됩니다. 정수 오버플로 검사가 켜지고 피연산자의 값이 최대 음SByte수이거나 LongShortInteger예외가 System.OverflowException throw되는 경우 그렇지 않으면 피연산자의 값이 최대 음SByte수, ShortInteger또는 Long결과가 같은 값이고 오버플로가 보고되지 않는 경우

SingleDouble. 결과는 값 0 및 무한대를 포함하여 해당 기호가 반전된 피연산자의 값입니다. 피연산자는 NaN이면 결과도 NaN입니다.

Decimal; 결과는 0에서 피연산자를 빼서 계산됩니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
Sh(Sh) SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과

더하기 연산자

더하기 연산자는 두 피연산자의 합계를 계산합니다.

AdditionOperatorExpression
    : Expression '+' LineTerminator? Expression
    ;

더하기 연산자는 다음 형식에 대해 정의됩니다.

  • Byte, SByte, UShort, Short, UInteger, Integer, ULong, 및 Long. 정수 오버플로 검사가 켜지고 합계가 결과 형식의 범위를 벗어나면 예외가 System.OverflowException throw됩니다. 그렇지 않으면 오버플로가 보고되지 않으며 결과의 중요한 상위 비트가 삭제됩니다.

  • SingleDouble. 합계는 IEEE 754 산술 연산의 규칙에 따라 계산됩니다.

  • Decimal; 결과 값이 너무 커서 10진수 형식으로 나타내지 않으면 예외가 System.OverflowException throw됩니다. 결과 값이 너무 작아서 10진수 형식으로 나타내지 않으면 결과는 0입니다.

  • String; 두 String 피연산자는 함께 연결됩니다.

  • Date; 이 형식은 System.DateTime 오버로드된 더하기 연산자를 정의합니다. 내장 형식과 동일하기 때문에 System.DateTime 이러한 연산자는 Date 형식에서도 Date 사용할 수 있습니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
Sh(Sh) SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
SB SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
작성자 곁에 Sh(Sh) 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
미국 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
In 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
UI (사용자 인터페이스) 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
UL UL Si 하세요 실수하다 실수하다 하세요 산부인과
Si 하세요 실수하다 실수하다 하세요 산부인과
Si Si 하세요 실수하다 실수하다 하세요 산부인과
권장 사항 하세요 실수하다 실수하다 하세요 산부인과
세인트 실수하다 세인트 산부인과
채널 세인트 세인트 산부인과
세인트 세인트 산부인과
Ob 산부인과

빼기 연산자

빼기 연산자는 첫 번째 피연산자에서 두 번째 피연산자를 뺍니다.

SubtractionOperatorExpression
    : Expression '-' LineTerminator? Expression
    ;

빼기 연산자는 다음 형식에 대해 정의됩니다.

  • Byte, SByte, UShort, Short, UInteger, Integer, ULong, 및 Long. 정수 오버플로 검사가 켜지고 그 차이가 결과 형식의 범위를 벗어나면 예외가 System.OverflowException throw됩니다. 그렇지 않으면 오버플로가 보고되지 않으며 결과의 중요한 상위 비트가 삭제됩니다.

  • SingleDouble. 차이는 IEEE 754 산술의 규칙에 따라 계산됩니다.

  • Decimal; 결과 값이 너무 커서 10진수 형식으로 나타내지 않으면 예외가 System.OverflowException throw됩니다. 결과 값이 너무 작아서 10진수 형식으로 나타내지 않으면 결과는 0입니다.

  • Date; 이 형식은 System.DateTime 오버로드된 빼기 연산자를 정의합니다. 내장 형식과 동일하기 때문에 System.DateTime 이러한 연산자는 Date 형식에서도 Date 사용할 수 있습니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
Sh(Sh) SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
SB SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
작성자 곁에 Sh(Sh) 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
미국 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
In 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
UI (사용자 인터페이스) 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
UL UL Si 하세요 실수하다 실수하다 하세요 산부인과
Si 하세요 실수하다 실수하다 하세요 산부인과
Si Si 하세요 실수하다 실수하다 하세요 산부인과
권장 사항 하세요 실수하다 실수하다 하세요 산부인과
실수하다 실수하다 실수하다 실수하다
채널 실수하다 실수하다 실수하다
세인트 하세요 산부인과
Ob 산부인과

곱하기 연산자

곱하기 연산자는 두 피연산자의 곱을 계산합니다.

MultiplicationOperatorExpression
    : Expression '*' LineTerminator? Expression
    ;

곱하기 연산자는 다음 형식에 대해 정의됩니다.

  • Byte, SByte, UShort, Short, UInteger, Integer, ULong, 및 Long. 정수 오버플로 검사가 켜지고 제품이 결과 형식의 범위를 벗어나면 예외가 System.OverflowException throw됩니다. 그렇지 않으면 오버플로가 보고되지 않으며 결과의 중요한 상위 비트가 삭제됩니다.

  • SingleDouble. 제품은 IEEE 754 산술 연산의 규칙에 따라 계산됩니다.

  • Decimal; 결과 값이 너무 커서 10진수 형식으로 나타내지 않으면 예외가 System.OverflowException throw됩니다. 결과 값이 너무 작아서 10진수 형식으로 나타내지 않으면 결과는 0입니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
Sh(Sh) SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
SB SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
작성자 곁에 Sh(Sh) 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
미국 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
In 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
UI (사용자 인터페이스) 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
UL UL Si 하세요 실수하다 실수하다 하세요 산부인과
Si 하세요 실수하다 실수하다 하세요 산부인과
Si Si 하세요 실수하다 실수하다 하세요 산부인과
권장 사항 하세요 실수하다 실수하다 하세요 산부인과
실수하다 실수하다 실수하다 실수하다
채널 실수하다 실수하다 실수하다
세인트 하세요 산부인과
Ob 산부인과

나누기 연산자

나누기 연산자는 두 피연산자의 몫을 계산합니다. 일반(부동 소수점) 나누기 연산자와 정수 나누기 연산자의 두 가지 나누기 연산자가 있습니다.

DivisionOperatorExpression
    : FPDivisionOperatorExpression
    | IntegerDivisionOperatorExpression
    ;

FPDivisionOperatorExpression
    : Expression '/' LineTerminator? Expression
    ;

IntegerDivisionOperatorExpression
    : Expression '\\' LineTerminator? Expression
    ;

일반 나누기 연산자는 다음 형식에 대해 정의됩니다.

  • SingleDouble. 몫은 IEEE 754 산술 규칙에 따라 계산됩니다.

  • Decimal; 오른쪽 피연산자의 값이 0이면 예외가 System.DivideByZeroException throw됩니다. 결과 값이 너무 커서 10진수 형식으로 나타내지 않으면 예외가 System.OverflowException throw됩니다. 결과 값이 너무 작아서 10진수 형식으로 나타낼 수 없는 경우 결과는 0입니다. 결과 배율(반올림 전)은 정확한 결과와 동일한 결과를 유지하는 기본 눈금과 가장 가까운 배율입니다. 기본 설정 눈금은 첫 번째 피연산자의 배율로 두 번째 피연산자의 배율을 줄입니다.

일반 연산자 확인 규칙에 따라 정규식은 피IntegerShort연산자와 같은 Byte형식의 피연산자 간에만 분할되며 Long 두 피연산자가 모두 형식Decimal으로 변환됩니다. 그러나 두 형식이 모두 없는 경우 나누기 연산자에서 연산자 확인을 수행하는 경우 DecimalDouble 보다 Decimal좁은 것으로 간주됩니다. 분열이 분열보다 Decimal 더 효율적이기 때문에 Double 이 규칙이 따릅니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 Si 하세요 실수하다 실수하다 하세요 산부인과
SB 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 Si 하세요 실수하다 실수하다 하세요 산부인과
작성자 하세요 하세요 하세요 하세요 하세요 하세요 하세요 Si 하세요 실수하다 실수하다 하세요 산부인과
Sh(Sh) 하세요 하세요 하세요 하세요 하세요 하세요 Si 하세요 실수하다 실수하다 하세요 산부인과
미국 하세요 하세요 하세요 하세요 하세요 Si 하세요 실수하다 실수하다 하세요 산부인과
In 하세요 하세요 하세요 하세요 Si 하세요 실수하다 실수하다 하세요 산부인과
UI (사용자 인터페이스) 하세요 하세요 하세요 Si 하세요 실수하다 실수하다 하세요 산부인과
Lo(Lo) 하세요 하세요 Si 하세요 실수하다 실수하다 하세요 산부인과
UL 하세요 Si 하세요 실수하다 실수하다 하세요 산부인과
Si 하세요 실수하다 실수하다 하세요 산부인과
Si Si 하세요 실수하다 실수하다 하세요 산부인과
권장 사항 하세요 실수하다 실수하다 하세요 산부인과
실수하다 실수하다 실수하다 실수하다
채널 실수하다 실수하다 실수하다
세인트 하세요 산부인과
Ob 산부인과

정수 나누기 연산자는 , ,SByteUShort, Short, ULongUIntegerInteger및 에 대해 Byte정의됩니다.Long 오른쪽 피연산자의 값이 0이면 예외가 System.DivideByZeroException throw됩니다. 나누기는 결과를 0으로 반올림하고 결과의 절대값은 두 피연산자의 몫의 절대값보다 작은 가능한 가장 큰 정수입니다. 결과는 두 피연산자의 부호가 같을 때 0 또는 양수이고, 두 피연산자의 부호가 반대인 경우 0 또는 음수입니다. 왼쪽 피연산자는 최대 음SByte수, IntegerShort또는 Long오른쪽 피연산자인 -1경우 오버플로가 발생합니다. 정수 오버플로 검사가 켜 System.OverflowException 지면 예외가 throw됩니다. 그렇지 않으면 오버플로가 보고되지 않고 결과는 왼쪽 피연산자의 값이 됩니다.

메모. 부호 없는 형식에 대한 두 피연산자는 항상 0 또는 양수이므로 결과는 항상 0이거나 양수입니다. 식의 결과는 항상 두 피연산자 중 가장 큰 피연산자보다 작거나 같으므로 오버플로가 발생할 수 없습니다. 따라서 두 개의 부호 없는 정수로 정수 나누기를 위해 정수 오버플로 검사가 수행되지 않습니다. 결과는 왼쪽 피연산자의 형식입니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
Sh(Sh) SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
SB SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
작성자 곁에 Sh(Sh) 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
미국 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
In 안으로 Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
UI (사용자 인터페이스) 사용자 인터페이스 (UI) Lo(Lo) UL Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
UL UL Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
Si Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
권장 사항 Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
실수하다 실수하다 실수하다 실수하다
채널 실수하다 실수하다 실수하다
세인트 Lo(Lo) 산부인과
Ob 산부인과

Mod 연산자

Mod (modulo) 연산자는 두 피연산자 간의 나누기의 나머지 부분을 계산합니다.

ModuloOperatorExpression
    : Expression 'Mod' LineTerminator? Expression
    ;

Mod 연산자는 다음 형식에 대해 정의됩니다.

  • Byte,SByte, UShort, Short, UIntegerIntegerULong 및 .Long x Mod y의 결과는 x - (x \ y) * y에 의해 생성된 값입니다. 0이면 y 예외가 System.DivideByZeroException throw됩니다. 모듈로 연산자는 오버플로를 일으키지 않습니다.

  • SingleDouble. 나머지는 IEEE 754 산술 규칙에 따라 계산됩니다.

  • Decimal; 오른쪽 피연산자의 값이 0이면 예외가 System.DivideByZeroException throw됩니다. 결과 값이 너무 커서 10진수 형식으로 나타내지 않으면 예외가 System.OverflowException throw됩니다. 결과 값이 너무 작아서 10진수 형식으로 나타낼 수 없는 경우 결과는 0입니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
Sh(Sh) SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
SB SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
작성자 곁에 Sh(Sh) 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
미국 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
In 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
UI (사용자 인터페이스) 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
UL UL Si 하세요 실수하다 실수하다 하세요 산부인과
Si 하세요 실수하다 실수하다 하세요 산부인과
Si Si 하세요 실수하다 실수하다 하세요 산부인과
권장 사항 하세요 실수하다 실수하다 하세요 산부인과
실수하다 실수하다 실수하다 실수하다
채널 실수하다 실수하다 실수하다
세인트 하세요 산부인과
Ob 산부인과

지수 연산자

지수 연산자는 두 번째 피연산자의 전원으로 발생된 첫 번째 피연산자를 계산합니다.

ExponentOperatorExpression
    : Expression '^' LineTerminator? Expression
    ;

지수 연산자는 형식 Double에 대해 정의됩니다. 이 값은 IEEE 754 산술 규칙에 따라 계산됩니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 실수하다 실수하다 하세요 산부인과
SB 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 실수하다 실수하다 하세요 산부인과
작성자 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 실수하다 실수하다 하세요 산부인과
Sh(Sh) 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 실수하다 실수하다 하세요 산부인과
미국 하세요 하세요 하세요 하세요 하세요 하세요 하세요 하세요 실수하다 실수하다 하세요 산부인과
In 하세요 하세요 하세요 하세요 하세요 하세요 하세요 실수하다 실수하다 하세요 산부인과
UI (사용자 인터페이스) 하세요 하세요 하세요 하세요 하세요 하세요 실수하다 실수하다 하세요 산부인과
Lo(Lo) 하세요 하세요 하세요 하세요 하세요 실수하다 실수하다 하세요 산부인과
UL 하세요 하세요 하세요 하세요 실수하다 실수하다 하세요 산부인과
하세요 하세요 하세요 실수하다 실수하다 하세요 산부인과
Si 하세요 하세요 실수하다 실수하다 하세요 산부인과
권장 사항 하세요 실수하다 실수하다 하세요 산부인과
실수하다 실수하다 실수하다 실수하다
채널 실수하다 실수하다 실수하다
세인트 하세요 산부인과
Ob 산부인과

관계형 연산자

관계형 연산자는 값을 서로 비교합니다. 비교 연산자는 =, , <<>, ><=>=.

RelationalOperatorExpression
    : Expression '=' LineTerminator? Expression
    | Expression '<' '>' LineTerminator? Expression
    | Expression '<' LineTerminator? Expression
    | Expression '>' LineTerminator? Expression
    | Expression '<' '=' LineTerminator? Expression
    | Expression '>' '=' LineTerminator? Expression
    ;

모든 관계형 연산자는 값을 생성합니다 Boolean .

관계형 연산자는 다음과 같은 일반적인 의미를 갖습니다.

  • 연산자는 = 두 피연산자가 같은지 여부를 테스트합니다.

  • 연산자는 <> 두 피연산자가 같지 않은지 여부를 테스트합니다.

  • 연산자는 < 첫 번째 피연산자가 두 번째 피연산자보다 작은지 여부를 테스트합니다.

  • 연산자는 > 첫 번째 피연산자가 두 번째 피연산자보다 큰지 테스트합니다.

  • 연산자는 <= 첫 번째 피연산자가 두 번째 피연산자보다 작거나 같은지 테스트합니다.

  • 연산자는 >= 첫 번째 피연산자가 두 번째 피연산자보다 크거나 같은지 테스트합니다.

관계형 연산자는 다음 형식에 대해 정의됩니다.

  • Boolean; 연산자는 두 피연산자의 진리 값을 비교합니다. True 는 숫자 값과 일치하는 보다 False작은 것으로 간주됩니다.

  • Byte, SByte, UShort, Short, UInteger, Integer, ULong, 및 Long. 연산자는 두 정수 피연산자의 숫자 값을 비교합니다.

  • SingleDouble. 연산자는 IEEE 754 표준의 규칙에 따라 피연산자를 비교합니다.

  • Decimal; 연산자는 두 소수 피연산자의 숫자 값을 비교합니다.

  • Date; 연산자는 두 날짜/시간 값을 비교한 결과를 반환합니다.

  • Char; 연산자는 두 유니코드 값을 비교한 결과를 반환합니다.

  • String; 연산자는 이진 비교 또는 텍스트 비교를 사용하여 두 값을 비교한 결과를 반환합니다. 사용되는 비교는 컴파일 환경 및 문에 Option Compare 의해 결정됩니다. 이진 비교는 각 문자열에 있는 각 문자의 숫자 유니코드 값이 같은지 여부를 결정합니다. 텍스트 비교는 .NET Framework에서 사용 중인 현재 문화권을 기반으로 유니코드 텍스트 비교를 수행합니다. 문자열 비교를 수행할 때 null 값은 문자열 리터럴 ""과 동일합니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 산부인과
SB SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
작성자 곁에 Sh(Sh) 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
미국 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
In 안으로 Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
UI (사용자 인터페이스) 사용자 인터페이스 (UI) Lo(Lo) UL Si 하세요 실수하다 실수하다 하세요 산부인과
Lo(Lo) Lo(Lo) Si 하세요 실수하다 실수하다 하세요 산부인과
UL UL Si 하세요 실수하다 실수하다 하세요 산부인과
Si 하세요 실수하다 실수하다 하세요 산부인과
Si Si 하세요 실수하다 실수하다 하세요 산부인과
권장 사항 하세요 실수하다 실수하다 하세요 산부인과
실수하다 산부인과
채널 채널 세인트 산부인과
세인트 세인트 산부인과
Ob 산부인과

Like 연산자

연산자는 Like 문자열이 지정된 패턴과 일치하는지 여부를 결정합니다.

LikeOperatorExpression
    : Expression 'Like' LineTerminator? Expression
    ;

Like 연산자는 형식에 대해 정의됩니다String. 첫 번째 피연산자는 일치하는 문자열이고 두 번째 피연산자는 일치시킬 패턴입니다. 패턴은 유니코드 문자로 구성됩니다. 다음 문자 시퀀스에는 특별한 의미가 있습니다.

  • 문자 ? 는 모든 단일 문자와 일치합니다.

  • 문자 * 는 0개 이상의 문자와 일치합니다.

  • 문자 # 는 한 자리(0-9)와 일치합니다.

  • 대괄호([ab...])로 둘러싸인 문자 목록은 목록의 모든 단일 문자와 일치합니다.

  • 대괄호로 둘러싸여 있고 느낌표([!ab...])가 접두사로 지정된 문자 목록은 문자 목록에 없는 단일 문자와 일치합니다.

  • 하이픈(-)으로 구분된 문자 목록의 두 문자는 첫 번째 문자로 시작하고 두 번째 문자로 끝나는 유니코드 문자 범위를 지정합니다. 두 번째 문자가 첫 번째 문자보다 정렬 순서가 아닌 경우 런타임 예외가 발생합니다. 문자 목록의 시작 또는 끝에 나타나는 하이픈은 자신을 지정합니다.

특수 문자 왼쪽 대괄호([), 물음표(?), 숫자 기호(#) 및 별표(*)와 일치하려면 대괄호를 묶어야 합니다. 오른쪽 대괄호(])는 그룹 내에서 자체와 일치하도록 사용할 수 없지만 그룹 외부에서 개별 문자로 사용할 수 있습니다. 문자 시퀀스는 [] 문자열 리터럴 ""로 간주됩니다.

문자 목록의 문자 비교 및 순서는 사용 중인 비교 유형에 따라 달라집니다. 이진 비교를 사용하는 경우 문자 비교 및 순서는 숫자 유니코드 값을 기반으로 합니다. 텍스트 비교를 사용하는 경우 문자 비교 및 순서 지정은 .NET Framework에서 사용되는 현재 로캘을 기반으로 합니다.

일부 언어에서는 알파벳의 특수 문자가 두 개의 개별 문자를 나타내고 그 반대의 경우도 마찬가지입니다. 예를 들어 여러 언어는 문자를 사용하여 문자를 æa 나타내고 e 문자를 함께 표시할 때 문자를 나타내고 O 문자를 ^ 나타내는 Ô데 사용할 수 있습니다. 텍스트 비교를 사용할 때 연산자는 Like 이러한 문화권 동등성을 인식합니다. 이 경우 패턴 또는 문자열에서 단일 특수 문자가 발생하면 다른 문자열의 동일한 두 문자 시퀀스와 일치합니다. 마찬가지로, 대괄호로 묶인 패턴의 특수 문자(그 자체로, 목록 또는 범위)는 문자열에서 동등한 두 문자 시퀀스와 일치하며 그 반대의 경우도 마찬가지입니다.

Like 두 피연산자 Nothing 또는 한 피연산자의 기본 변환 String 이 있고 다른 피연산자는 빈 문자열 리터럴""인 것처럼 처리되는 NothingNothing 식에서.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
SB 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
작성자 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
Sh(Sh) 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
미국 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
In 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
UI (사용자 인터페이스) 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
Lo(Lo) 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
UL 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
세인트 세인트 세인트 세인트 세인트 세인트 산부인과
Si 세인트 세인트 세인트 세인트 세인트 산부인과
권장 사항 세인트 세인트 세인트 세인트 산부인과
세인트 세인트 세인트 산부인과
채널 세인트 세인트 산부인과
세인트 세인트 산부인과
Ob 산부인과

연결 연산자

ConcatenationOperatorExpression
    : Expression '&' LineTerminator? Expression
    ;

연결 연산자는 내장 값 형식의 nullable 버전을 포함하여 모든 내장 형식에 대해 정의됩니다. 또한 위에서 언급한 형식과 System.DBNull문자열로 Nothing 처리되는 형식 간의 연결을 위해 정의됩니다. 연결 연산자는 모든 피연산자를 변환합니다 String. 식에서 엄격한 의미 체계를 사용하는지 여부에 관계없이 모든 변환 String 이 확대되는 것으로 간주됩니다. System.DBNull 값은 리터럴 Nothing 형식으로 String변환됩니다. 런타임 오류를 throw하지 않고 값이 형식화된 리터럴 NothingString도 변환되는 nullable 값 형식입니다Nothing.

연결 작업을 수행하면 왼쪽에서 오른쪽으로 순서대로 두 피연산자의 연결인 문자열이 생성됩니다. 값 Nothing 은 빈 문자열 리터럴인 것처럼 처리됩니다 "".

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
SB 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
작성자 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
Sh(Sh) 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
미국 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
In 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
UI (사용자 인터페이스) 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
Lo(Lo) 세인트 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
UL 세인트 세인트 세인트 세인트 세인트 세인트 세인트 산부인과
세인트 세인트 세인트 세인트 세인트 세인트 산부인과
Si 세인트 세인트 세인트 세인트 세인트 산부인과
권장 사항 세인트 세인트 세인트 세인트 산부인과
세인트 세인트 세인트 산부인과
채널 세인트 세인트 산부인과
세인트 세인트 산부인과
Ob 산부인과

논리 연산자

And, NotOrXor 연산자를 논리 연산자라고 합니다.

LogicalOperatorExpression
    : 'Not' Expression
    | Expression 'And' LineTerminator? Expression
    | Expression 'Or' LineTerminator? Expression
    | Expression 'Xor' LineTerminator? Expression
    ;

논리 연산자는 다음과 같이 평가됩니다.

  • 형식의 Boolean 경우:

    • 논리 And 연산은 두 피연산자에서 수행됩니다.

    • 논리 Not 연산은 피연산자에서 수행됩니다.

    • 논리 Or 연산은 두 피연산자에서 수행됩니다.

    • 논리 배타적Or 연산은 두 피연산자에서 수행됩니다.

  • , ,, , , , , ULongLong및 모든 열거형 형식의 경우 Byte지정된 작업은 두 피연산자의 이진 표현의 각 비트에서 수행됩니다. IntegerUIntegerShortUShortSByte

    • And: 두 비트가 1이면 결과 비트가 1입니다. 그렇지 않으면 결과 비트가 0입니다.

    • Not: 비트가 0이면 결과 비트가 1입니다. 그렇지 않으면 결과 비트가 1입니다.

    • Or: 두 비트 중 하나가 1인 경우 결과 비트는 1입니다. 그렇지 않으면 결과 비트가 0입니다.

    • Xor: 두 비트 중 하나가 1이지만 두 비트가 아닌 경우 결과 비트는 1입니다. 그렇지 않으면 결과 비트는 0입니다(즉, 1 Xor 0 = 1, 1 1 Xor = 0).

  • 논리 연산 AndOr 자가 형식 Boolean?에 대해 해제되면 다음과 같이 값이 세 개인 부울 논리를 포함하도록 확장됩니다.

    • And 는 두 피연산자 모두 true이면 true로 계산됩니다. 피연산자 중 하나가 false이면 false이고, Nothing 그렇지 않으면.

    • Or 피연산자 중 하나가 true이면 true로 계산됩니다. false는 두 피연산자 모두 false입니다. Nothing 그렇지 않으면.

다음은 그 예입니다.

Module Test
    Sub Main()
        Dim x?, y? As Boolean

        x = Nothing
        y = True 

        If x Or y Then
            ' Will execute
        End If
    End Sub
End Module

메모. 이상적으로 논리 연산 And 자는 Or 부울 식에서 사용할 수 있는 모든 형식(즉, 구현 IsTrue 하는 형식 및 )에 사용할 수 있는 모든 형식에 대해 세 가지 값 논리를 사용하여 해제하고 IsFalse부울 식에서 사용할 수 있는 모든 형식에서 단락하는 OrElse 것과 동일한 방식으로 AndAlso 해제됩니다. 아쉽게도 3값 리프팅은 3값 리프팅에만 적용Boolean?되므로 세 가지 값 논리를 원하는 사용자 정의 형식은 nullable 버전을 정의하고 Or 연산자를 정의하여 And 수동으로 수행해야 합니다.

이러한 작업에서는 오버플로가 불가능합니다. 열거형 형식 연산자는 열거형 형식의 기본 형식에 대해 비트 연산을 수행하지만 반환 값은 열거형 형식입니다.

작업 유형이 아님:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
SB 곁에 Sh(Sh) 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과

또는 Xor 작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 산부인과
SB SB Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
작성자 곁에 Sh(Sh) 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
Sh(Sh) Sh(Sh) 안으로 안으로 Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
미국 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
In 안으로 Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
UI (사용자 인터페이스) 사용자 인터페이스 (UI) Lo(Lo) UL Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
UL UL Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
Si Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
권장 사항 Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과
실수하다 실수하다 실수하다 실수하다
채널 실수하다 실수하다 실수하다
세인트 Lo(Lo) 산부인과
Ob 산부인과

단락 논리 연산자

AndAlsoOrElse 연산자는 논리 연산자의 And 단락 버전입니다Or.

ShortCircuitLogicalOperatorExpression
    : Expression 'AndAlso' LineTerminator? Expression
    | Expression 'OrElse' LineTerminator? Expression
    ;

단락 동작으로 인해 첫 번째 피연산자를 평가한 후 연산자 결과가 알려진 경우 두 번째 피연산자는 런타임에 평가되지 않습니다.

단락 논리 연산자는 다음과 같이 평가됩니다.

  • 연산의 첫 번째 피연산자가 AndAlso 해당 연산자에서 IsFalse True로 False 평가되거나 반환되면 식은 첫 번째 피연산자를 반환합니다. 그렇지 않으면 두 번째 피연산자가 평가되고 두 결과에 대해 논리 And 연산이 수행됩니다.

  • 연산의 첫 번째 피연산자가 OrElse 해당 연산자에서 IsTrue True로 True 평가되거나 반환되면 식은 첫 번째 피연산자를 반환합니다. 그렇지 않으면 두 번째 피연산자가 평가되고 두 결과에 대해 논리 Or 연산이 수행됩니다.

AndAlsoOrElse 연산자는 형식 Boolean또는 다음 연산자를 오버로드하는 모든 형식 T 에 대해 정의됩니다.

Public Shared Operator IsTrue(op As T) As Boolean
Public Shared Operator IsFalse(op As T) As Boolean

해당 또는 연산자를 오버로드할 뿐만 아니라 다음을 And 수행합니다 Or .

Public Shared Operator And(op1 As T, op2 As T) As T
Public Shared Operator Or(op1 As T, op2 As T) As T

또는 OrElse 연산자를 AndAlso 평가할 때 첫 번째 피연산자는 한 번만 평가되고 두 번째 피연산자는 정확히 한 번만 평가되거나 평가되지 않습니다. 예를 들어 다음 코드를 고려합니다.

Module Test
    Function TrueValue() As Boolean
        Console.Write(" True")
        Return True
    End Function

    Function FalseValue() As Boolean
        Console.Write(" False")
        Return False
    End Function

    Sub Main()
        Console.Write("And:")
        If FalseValue() And TrueValue() Then
        End If
        Console.WriteLine()

        Console.Write("Or:")
        If TrueValue() Or FalseValue() Then
        End If
        Console.WriteLine()

        Console.Write("AndAlso:")
        If FalseValue() AndAlso TrueValue() Then
        End If
        Console.WriteLine()

        Console.Write("OrElse:")
        If TrueValue() OrElse FalseValue() Then
        End If
        Console.WriteLine()
    End Sub
End Module

다음 결과를 출력합니다.

And: False True
Or: True False
AndAlso: False
OrElse: True

해제된 형식의 AndAlso 연산자 OrElse 에서 첫 번째 피연산자가 null Boolean?이면 두 번째 피연산자가 계산되지만 결과는 항상 null Boolean?입니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
실수하다 실수하다 산부인과
SB 실수하다 실수하다 산부인과
작성자 실수하다 실수하다 산부인과
Sh(Sh) 실수하다 실수하다 산부인과
미국 실수하다 실수하다 산부인과
In 실수하다 실수하다 산부인과
UI (사용자 인터페이스) 실수하다 실수하다 산부인과
Lo(Lo) 실수하다 실수하다 산부인과
UL 실수하다 실수하다 산부인과
실수하다 실수하다 산부인과
Si 실수하다 실수하다 산부인과
권장 사항 실수하다 실수하다 산부인과
실수하다 실수하다 실수하다 실수하다
채널 실수하다 실수하다 실수하다
세인트 산부인과
Ob 산부인과

시프트 연산자

이진 연산 << 자이며 >> 비트 시프트 작업을 수행합니다.

ShiftOperatorExpression
    : Expression '<' '<' LineTerminator? Expression
    | Expression '>' '>' LineTerminator? Expression
    ;

연산자는 , , SByte, UShortShort, IntegerUIntegerULongLong 형식에 대해 Byte정의됩니다. 다른 이진 연산자와 달리 시프트 연산의 결과 형식은 연산자가 왼쪽 피연산자만 있는 단항 연산자인 것처럼 결정됩니다. 오른쪽 피연산자의 형식은 암시적으로 변환할 수 Integer 있어야 하며 작업의 결과 형식을 결정하는 데 사용되지 않습니다.

<< 연산자는 첫 번째 피연산자의 비트가 시프트 양으로 지정된 위치 수를 왼쪽으로 이동하도록 합니다. 결과 형식 범위를 벗어난 상위 비트는 삭제되고 낮은 순서로 비워진 비트 위치는 0으로 채워집니다.

>> 연산자는 첫 번째 피연산자의 비트가 시프트 양으로 지정된 위치 수를 오른쪽으로 이동하도록 합니다. 낮은 순서의 비트는 삭제되고 왼쪽 피연산자는 양수이면 고차 비워진 비트 위치가 0으로 설정되고 음수인 경우 1로 설정됩니다. 왼쪽 피연산자의 형식ByteUShortUIntegerULong 거나 빈 상위 비트가 0으로 채워진 경우

시프트 연산자는 첫 번째 피연산자의 기본 표현 비트를 두 번째 피연산자의 양만큼 이동합니다. 두 번째 피연산자의 값이 첫 번째 피연산자의 비트 수보다 크거나 음수이면 시프트 크기는 다음과 SizeMask 같이 RightOperand And SizeMask 계산됩니다.

LeftOperand 형식 SizeMask
Byte, SByte 7 (&H7)
UShort, Short 15 (&HF)
UInteger, Integer 31 (&H1F)
ULong, Long 63 (&H3F)

시프트 크기가 0이면 작업 결과가 첫 번째 피연산자의 값과 동일합니다. 이러한 작업에서는 오버플로가 불가능합니다.

작업 유형:

SB 작성자 Sh(Sh) 미국 In UI (사용자 인터페이스) Lo(Lo) UL Si 권장 사항 채널 세인트 Ob
Sh(Sh) SB 곁에 Sh(Sh) 미국 안으로 사용자 인터페이스 (UI) Lo(Lo) UL Lo(Lo) Lo(Lo) Lo(Lo) 실수하다 실수하다 Lo(Lo) 산부인과

부울 식

부울 식은 true인지 아니면 false인지 확인하기 위해 테스트할 수 있는 식입니다.

BooleanExpression
    : Expression
    ;

기본 설정 순서대로 부울 식에 형식 T 을 사용할 수 있습니다.

  • T Boolean 또는 Boolean?

  • T 에 대한 확장 변환이 있습니다. Boolean

  • T 에 대한 확장 변환이 있습니다. Boolean?

  • T는 두 의사 연산자를 정의하고 IsFalse. IsTrue

  • T 로의 변환을 포함하지 않는 축소 변환 Boolean?Boolean 이 있습니다 Boolean?.

  • T 에는 축소 변환이 있습니다 Boolean.

메모. 해제된 경우 Option Strict 축소 변환 Boolean 이 있는 식은 컴파일 시간 오류 없이 수락되지만 언어는 연산자 IsTrue (있는 경우)를 선호한다는 점에 유의해야 합니다. 이는 Option Strict 언어에서 허용되지 않는 내용만 변경하고 식의 실제 의미를 변경하지 않기 때문입니다. 따라서 에 IsTrue 관계없이 항상 축소 변환보다 선호되어야 합니다 Option Strict.

예를 들어 다음 클래스는 확대 변환 Boolean을 정의하지 않습니다. 따라서 문에서 해당 메서드를 If 사용하면 연산자를 호출합니다 IsTrue .

Class MyBool
    Public Shared Widening Operator CType(b As Boolean) As MyBool
        ...
    End Operator

    Public Shared Narrowing Operator CType(b As MyBool) As Boolean
        ...
    End Operator

    Public Shared Operator IsTrue(b As MyBool) As Boolean
        ...
    End Operator

    Public Shared Operator IsFalse(b As MyBool) As Boolean
        ...
    End Operator
End Class

Module Test
    Sub Main()
        Dim b As New MyBool

        If b Then Console.WriteLine("True")
    End Sub
End Module

부울 식이 형식화되거나 변환되는 BooleanBoolean?경우 값이 true이고 그렇지 않으면 false입니다 True .

그렇지 않으면 부울 식은 연산자를 IsTrue 호출하고 연산자가 반환되면 반환 TrueTrue합니다. 그렇지 않으면 false이지만 연산자를 IsFalse 호출하지는 않습니다.

다음 예제 Integer 에서는 축소 변환이 Boolean있으므로 null은 둘 다 Boolean? (null Integer?Boolean생성) 및 Boolean (예외를 throw하는) 축소 변환을 가집니다. 축소 변환 Boolean? 이 기본 설정되므로 부울 식으로 "i"의 값이 False됩니다.

Dim i As Integer? = Nothing
If i Then Console.WriteLine()

람다 식

람다 식람다 메서드라는 익명 메서드를 정의합니다. 람다 메서드를 사용하면 대리자 형식을 사용하는 다른 메서드에 "인라인" 메서드를 쉽게 전달할 수 있습니다.

LambdaExpression
    : SingleLineLambda
    | MultiLineLambda
    ;

SingleLineLambda
    : LambdaModifier* 'Function' ( OpenParenthesis ParameterList? CloseParenthesis )? Expression
    | 'Sub' ( OpenParenthesis ParameterList? CloseParenthesis )? Statement
    ;

MultiLineLambda
    : MultiLineFunctionLambda
    | MultiLineSubLambda
    ;

MultiLineFunctionLambda
    : LambdaModifier? 'Function' ( OpenParenthesis ParameterList? CloseParenthesis )? ( 'As' TypeName )? LineTerminator
      Block
      'End' 'Function'
    ;

MultiLineSubLambda
    : LambdaModifier? 'Sub' ( OpenParenthesis ParameterList? CloseParenthesis )? LineTerminator
      Block
      'End' 'Sub'
    ;

LambdaModifier
    : 'Async' | 'Iterator'
    ;

예:

Module Test
    Delegate Function IntFunc(x As Integer) As Integer

    Sub Apply(a() As Integer, func As IntFunc)
        For index As Integer = 0 To a.Length - 1
            a(index) = func(a(index))
        Next index
    End Sub

    Sub Main()
        Dim a() As Integer = { 1, 2, 3, 4 }

        Apply(a, Function(x As Integer) x * 2)

        For Each value In a
            Console.Write(value & " ")
        Next value
    End Sub
End Module

는 다음을 출력합니다.

2 4 6 8

람다 식은 선택적 한정자 Async 또는 키워드 Function 또는 IteratorSub 매개 변수 목록으로 시작합니다. 람다 식의 매개 변수는 선언 OptionalParamArray 할 수 없거나 특성을 가질 수 없습니다. 일반 메서드와 달리 람다 메서드에 대한 매개 변수 형식을 생략해도 자동으로 유추 Object되지는 않습니다. 대신 람다 메서드를 다시 분류하면 생략된 매개 변수 형식 및 ByRef 한정자가 대상 형식에서 유추됩니다. 이전 예제에서 람다 식은 다음과 같이 Function(x) x * 2작성되었을 수 있으며 람다 메서드를 사용하여 대리자 형식의 x 인스턴스 IntFunc 를 만들 때 형식을 유추했을 것입니다Integer. 지역 변수 유추와 달리 람다 메서드 매개 변수가 형식을 생략하지만 배열 또는 null 허용 이름 한정자가 있는 경우 컴파일 시간 오류가 발생합니다.

정규 람다 식은 한정자도 없는 AsyncIterator 식입니다.

반복기 람다 식은 한 Iterator 정자와 한정자가 없는 Async 식입니다. 함수여야 합니다. 값으로 재분류되는 경우 반환 형식이 ByRef 매개 변수가 없는 대리자 형식 IEnumerator또는 IEnumerable(Of T)IEnumerableIEnumerator(Of T) 일부 T형식의 값으로만 다시 분류할 수 있습니다.

비동기 람다 식은 한정자와 한정자가 없는 Iterator 식입니다Async. 비동기 하위 람다는 ByRef 매개 변수가 없는 하위 대리자 형식의 값으로만 재분류할 수 있습니다. 비동기 함수 람다는 반환 형식이 있거나 Task(Of T) 일부T이며 ByRef 매개 변수가 없는 함수 대리자 형식 Task 의 값으로만 재분류할 수 있습니다.

람다 식은 한 줄 또는 여러 줄일 수 있습니다. 한 줄 Function 람다 식에는 람다 메서드에서 반환된 값을 나타내는 단일 식이 포함되어 있습니다. 한 줄 Sub 람다 식은 닫 StatementTerminator히지 않고 단일 문을 포함합니다. 다음은 그 예입니다.

Module Test
    Sub Do(a() As Integer, action As Action(Of Integer))
        For index As Integer = 0 To a.Length - 1
            action(a(index))
        Next index
    End Sub

    Sub Main()
        Dim a() As Integer = { 1, 2, 3, 4 }

        Do(a, Sub(x As Integer) Console.WriteLine(x))
    End Sub
End Module

한 줄 람다 구문은 다른 모든 식 및 문보다 덜 단단히 바인딩됩니다. 예를 들어 ""는 "Function() x + 5가 아니라(Function() x) + 5 "Function() (x+5)""에 해당합니다. 모호성을 방지하기 위해 한 줄 Sub 람다 식에는 Dim 문이나 레이블 선언 문이 포함되지 않을 수 있습니다. 또한 괄호로 묶지 않는 한 한 줄 Sub 람다 식에는 콜론 ":", 멤버 액세스 연산자 ".", 사전 멤버 액세스 연산자 "!" 또는 열린 괄호 "("가 바로 뒤에 올 수 없습니다. 블록 문(With,, , SyncLock, If...EndIf, WhileFor,DoUsing) 또는 .을 포함할 수 없습니다ResumeOnError.

메모. 람다 식 Function(i) x=i에서 본문은 (같음 여부를 xi 테스트하는)으로 해석됩니다. 그러나 람다 식 Sub(i) x=i에서 본문은 문(할당)으로 해석됩니다 ix.

여러 줄 람다 식은 문 블록을 포함하며 적절한 End 문(예: End Function 또는 End Sub)으로 끝나야 합니다. 일반 메서드와 마찬가지로 여러 줄 람다 메서드 Function 또는 Sub 문과 End 문은 자체 줄에 있어야 합니다. 다음은 그 예입니다.

' Error: Function statement must be on its own line!
Dim x = Sub(x As Integer) : Console.WriteLine(x) : End Sub

' OK
Dim y = Sub(x As Integer)
               Console.WriteLine(x)
          End Sub

여러 줄 Function 람다 식은 반환 형식을 선언할 수 있지만 특성을 배치할 수는 없습니다. 여러 줄 Function 람다 식이 반환 형식을 선언하지 않지만 반환 형식을 람다 식이 사용되는 컨텍스트에서 유추할 수 있는 경우 해당 반환 형식이 사용됩니다. 그렇지 않으면 함수의 반환 형식이 다음과 같이 계산됩니다.

  • 정규 람다 식에서 반환 형식은 문 블록의 모든 문에 있는 식의 Return 주요 형식입니다.

  • 비동기 람다 식에서 반환 형식은 Task(Of T)T 문 블록의 모든 문에 있는 식의 Return 주요 형식입니다.

  • 반복기 람다 식에서 반환 형식은 IEnumerable(Of T)T 문 블록의 모든 Yield 문에 있는 식의 주요 형식입니다.

다음은 그 예입니다.

Function f(min As Integer, max As Integer) As IEnumerable(Of Integer)
    If min > max Then Throw New ArgumentException()
    Dim x = Iterator Function()
                  For i = min To max
                    Yield i
                Next
               End Function

    ' infers x to be a delegate with return type IEnumerable(Of Integer)
    Return x()
End Function

모든 경우에 문(각각Yield)이 없거나 Return 해당 문 중에서 주요 형식이 없고 엄격한 의미 체계를 사용하는 경우 컴파일 시간 오류가 발생합니다. 그렇지 않으면 주 형식이 암시적으로 Object발생합니다.

반환 형식은 연결할 수 없는 경우에도 모든 Return 문에서 계산됩니다. 다음은 그 예입니다.

' Return type is Double
Dim x = Function()
              Return 10
               Return 10.50
          End Function

변수에 대한 이름이 없으므로 암시적 반환 변수는 없습니다.

여러 줄 람다 식 내의 문 블록에는 다음과 같은 제한 사항이 있습니다.

  • On ErrorResume 은 허용되지만 Try 문은 허용되지 않습니다.

  • 정적 로컬은 여러 줄 람다 식에서 선언할 수 없습니다.

  • 일반 분기 규칙이 그 안에 적용되지만 여러 줄 람다 식의 문 블록으로 또는 밖으로 분기할 수는 없습니다. 다음은 그 예입니다.

    Label1:
    Dim x = Sub()
                   ' Error: Cannot branch out
                   GoTo Label1
    
                   ' OK: Wholly within the lamba.
                   GoTo Label2:
              Label2:
              End Sub
    
    ' Error: Cannot branch in
    GoTo Label2
    

람다 식은 포함하는 형식에 선언된 무명 메서드와 거의 동일합니다. 초기 예제는 대략 다음과 같습니다.

Module Test
    Delegate Function IntFunc(x As Integer) As Integer

    Sub Apply(a() As Integer, func As IntFunc)
        For index As Integer = 0 To a.Length - 1
            a(index) = func(a(index))
        Next index
    End Sub

    Function $Lambda1(x As Integer) As Integer
        Return x * 2
    End Function

    Sub Main()
        Dim a() As Integer = { 1, 2, 3, 4 }

        Apply(a, AddressOf $Lambda1)

        For Each value In a
            Console.Write(value & " ")
        Next value
    End Sub
End Module

폐쇄

람다 식은 포함하는 메서드 및 람다 식에 정의된 지역 변수 또는 매개 변수를 포함하여 범위의 모든 변수에 액세스할 수 있습니다. 람다 식이 지역 변수 또는 매개 변수를 참조하는 경우 람다 식은 닫기에 참조되는 변수를 캡처합니다. 클로저는 스택이 아닌 힙에 있는 개체이며 변수가 캡처되면 변수에 대한 모든 참조가 클로저로 리디렉션됩니다. 이렇게 하면 포함하는 메서드가 완료된 후에도 람다 식이 지역 변수 및 매개 변수를 계속 참조할 수 있습니다. 다음은 그 예입니다.

Module Test
    Delegate Function D() As Integer

    Function M() As D
        Dim x As Integer = 10
        Return Function() x
    End Function

    Sub Main()
        Dim y As D = M()

        ' Prints 10
        Console.WriteLine(y())
    End Sub
End Module

은 다음과 거의 동일합니다.

Module Test
    Delegate Function D() As Integer

    Class $Closure1
        Public x As Integer

        Function $Lambda1() As Integer
            Return x
        End Function
    End Class

    Function M() As D
        Dim c As New $Closure1()
        c.x = 10
        Return AddressOf c.$Lambda1
    End Function

    Sub Main()
        Dim y As D = M()

        ' Prints 10
        Console.WriteLine(y())
    End Sub
End Module

클로저는 지역 변수가 선언된 블록에 들어갈 때마다 지역 변수의 새 복사본을 캡처하지만 새 복사본은 이전 복사본의 값(있는 경우)으로 초기화됩니다. 다음은 그 예입니다.

Module Test
    Delegate Function D() As Integer

    Function M() As D()
        Dim a(9) As D

        For i As Integer = 0 To 9
            Dim x
            a(i) = Function() x
            x += 1
        Next i

        Return a
    End Function

    Sub Main()
        Dim y() As D = M()

        For i As Integer = 0 To 9
            Console.Write(y(i)() & " ")
        Next i
    End Sub
End Module

인쇄

1 2 3 4 5 6 7 8 9 10

대신에

9 9 9 9 9 9 9 9 9 9

블록을 입력할 때 닫기를 초기화해야 하므로 닫기를 사용하여 블록으로 들어갈 수 GoTo 있지만 해당 블록 외부에서 닫힌 블록으로 들어갈 수는 Resume 없습니다. 다음은 그 예입니다.

Module Test
    Sub Main()
        Dim a = 10

        If a = 10 Then
L1:
            Dim x = Function() a

            ' Valid, source is within block
            GoTo L2
L2:
        End If

        ' ERROR: target is inside block with closure
        GoTo L1
    End Sub
End Module

닫기에 캡처할 수 없으므로 다음이 람다 식 내에 나타날 수 없습니다.

  • 참조 매개 변수입니다.

  • 형식 Me 이 클래스가 아닌 경우 인스턴스 식(Me, MyClass, MyBase)입니다.

람다 식이 식의 일부인 경우 익명 형식 생성 식의 멤버입니다. 다음은 그 예입니다.

' Error: Lambda cannot refer to anonymous type field
Dim x = New With { .a = 12, .b = Function() .a }

ReadOnly 인스턴스 생성자의 인스턴스 변수 또는 ReadOnly 값이 아닌 컨텍스트에서 변수가 사용되는 공유 생성자의 공유 변수입니다. 다음은 그 예입니다.

Class C1
    ReadOnly F1 As Integer

    Sub New()
        ' Valid, doesn't modify F1
        Dim x = Function() F1

        ' Error, tries to modify F1
        Dim f = Function() ModifyValue(F1)
    End Sub

    Sub ModifyValue(ByRef x As Integer)
    End Sub
End Class

쿼리 식

쿼리 식은 쿼리 가능한 컬렉션의 요소에 일련의 쿼리 연산자를 적용하는 식입니다. 예를 들어 다음 식은 개체 컬렉션을 Customer 사용하고 워싱턴 주에 있는 모든 고객의 이름을 반환합니다.

Dim names = _
    From cust In Customers _
    Where cust.State = "WA" _
    Select cust.Name

쿼리 식은 연산자 From 또는 연산자를 Aggregate 사용하여 시작해야 하며 모든 쿼리 연산자로 끝날 수 있습니다. 쿼리 식의 결과는 값으로 분류됩니다. 식의 결과 형식은 식에서 마지막 쿼리 연산자의 결과 형식에 따라 달라집니다.

QueryExpression
    : FromOrAggregateQueryOperator QueryOperator*
    ;

FromOrAggregateQueryOperator
    : FromQueryOperator
    | AggregateQueryOperator
    ;

QueryOperator
    : FromQueryOperator
    | AggregateQueryOperator
    | SelectQueryOperator
    | DistinctQueryOperator
    | WhereQueryOperator
    | OrderByQueryOperator
    | PartitionQueryOperator
    | LetQueryOperator
    | GroupByQueryOperator
    | JoinOrGroupJoinQueryOperator
    ;

JoinOrGroupJoinQueryOperator
    : JoinQueryOperator
    | GroupJoinQueryOperator
    ;

범위 변수

일부 쿼리 연산자는 범위 변수라는 특수한 종류의 변수를 도입합니다. 범위 변수는 실제 변수가 아닙니다. 대신 입력 컬렉션에 대한 쿼리를 평가하는 동안 개별 값을 나타냅니다.

CollectionRangeVariableDeclarationList
    : CollectionRangeVariableDeclaration ( Comma CollectionRangeVariableDeclaration )*
    ;

CollectionRangeVariableDeclaration
    : Identifier ( 'As' TypeName )? 'In' LineTerminator? Expression
    ;

ExpressionRangeVariableDeclarationList
    : ExpressionRangeVariableDeclaration ( Comma ExpressionRangeVariableDeclaration )*
    ;

ExpressionRangeVariableDeclaration
    : Identifier ( 'As' TypeName )? Equals Expression
    ;

범위 변수는 도입 쿼리 연산자에서 쿼리 식의 끝 또는 해당 변수를 숨기는 쿼리 Select 연산자로 범위가 지정됩니다. 예를 들어 다음 쿼리에서

Dim waCusts = _
    From cust As Customer In Customers _
    Where cust.State = "WA"

From 쿼리 연산자는 컬렉션의 각 고객을 Customers 나타내는 범위 Customer 변수 cust 를 입력합니다. 그런 다음, 다음 Where 쿼리 연산자는 필터 식의 범위 변수 cust 를 참조하여 결과 컬렉션에서 개별 고객을 필터링할지 여부를 결정합니다.

범위 변수에는 컬렉션 범위 변수와 식 범위 변수 의 두 가지 유형 이 있습니다. 컬렉션 범위 변수는 쿼리되는 컬렉션의 요소에서 해당 값을 가져옵니다. 컬렉션 범위 변수 선언의 컬렉션 식은 해당 형식을 쿼리할 수 있는 값으로 분류해야 합니다. 컬렉션 범위 변수의 형식을 생략하면 컬렉션 식의 요소 형식으로 유추되거나 Object 컬렉션 식에 요소 형식이 없는 경우(즉, 메서드만 정의) 유추됩니다 Cast . 컬렉션 식을 쿼리할 수 없는 경우(즉, 컬렉션의 요소 형식을 유추할 수 없음) 컴파일 시간 오류가 발생합니다.

식 범위 변수는 컬렉션이 아닌 식으로 값을 계산하는 범위 변수입니다. 다음 예제 Select 에서 쿼리 연산자는 두 필드에서 계산된 식 cityState 범위 변수를 소개합니다.

Dim cityStates = _
    From cust As Customer In Customers _
    Select cityState = cust.City & "," & cust.State _
    Where cityState.Length() < 10

이러한 변수는 모호한 값일 수 있지만 식 범위 변수는 다른 범위 변수를 참조할 필요가 없습니다. 식 범위 변수에 할당된 식은 값으로 분류되어야 하며 지정된 경우 범위 변수의 형식으로 암시적으로 변환할 수 있어야 합니다.

Let 연산자에서만 식 범위 변수의 형식이 지정될 수 있습니다. 다른 연산자에서 또는 해당 형식이 지정되지 않은 경우 지역 변수 형식 유추를 사용하여 범위 변수의 형식을 결정합니다.

범위 변수는 그림자와 관련하여 지역 변수를 선언하는 규칙을 따라야 합니다. 따라서 범위 변수는 바깥쪽 메서드 또는 다른 범위 변수에서 지역 변수 또는 매개 변수의 이름을 숨길 수 없습니다(쿼리 연산자가 범위의 모든 현재 범위 변수를 구체적으로 숨기지 않는 한).

쿼리 가능한 형식

쿼리 식은 식을 컬렉션 형식에서 잘 알려진 메서드에 대한 호출로 변환하여 구현됩니다. 이러한 잘 정의된 메서드는 쿼리 가능한 컬렉션의 요소 형식과 컬렉션에서 실행되는 쿼리 연산자의 결과 형식을 정의합니다. 각 쿼리 연산자는 특정 변환이 구현에 따라 달라지지만 쿼리 연산자가 일반적으로 변환되는 메서드 또는 메서드를 지정합니다. 메서드는 다음과 같은 일반 형식을 사용하여 사양에 제공됩니다.

Function Select(selector As Func(Of T, R)) As CR

다음은 메서드에 적용됩니다.

  • 메서드는 컬렉션 형식의 인스턴스 또는 확장 멤버여야 하며 액세스할 수 있어야 합니다.

  • 모든 형식 인수를 유추할 수 있는 경우 메서드는 제네릭일 수 있습니다.

  • 메서드가 오버로드될 수 있습니다. 이 경우 오버로드 확인은 정확히 사용할 메서드를 결정하는 데 사용됩니다.

  • 일치하는 형식과 반환 Func 형식을 비롯한 시그니처가 동일한 경우 대리자 형식 대신 다른 대리 Func 자 형식을 사용할 수 있습니다.

  • 일치하는 형식 System.Linq.Expressions.Expression(Of D) 과 반환 Func 형식을 포함하여 시그니처가 동일한 대리자 형식인 경우 D 대리자 형식 대신 Func 형식을 사용할 수 있습니다.

  • 형식 T 은 입력 컬렉션의 요소 형식을 나타냅니다. 컬렉션 형식에 의해 정의된 모든 메서드는 컬렉션 형식을 쿼리할 수 있도록 동일한 입력 요소 형식을 가져야 합니다.

  • S 인을 수행하는 쿼리 연산자의 경우 두 번째 입력 컬렉션의 요소 형식을 나타냅니다.

  • 이 형식 K 은 키 역할을 하는 범위 변수 집합이 있는 쿼리 연산자의 경우 키 형식을 나타냅니다.

  • 이 형식 N 은 숫자 형식으로 사용되는 형식을 나타냅니다(기본 숫자 형식이 아닌 사용자 정의 형식일 수 있음).

  • 이 형식 B 은 부울 식에서 사용할 수 있는 형식을 나타냅니다.

  • 쿼리 연산자가 결과 컬렉션을 생성하는 경우 형식 R 은 결과 컬렉션의 요소 형식을 나타냅니다. R 는 쿼리 연산자가 끝날 때 범위의 범위 변수 수에 따라 달라집니다. 단일 범위 변수가 범위에 R 있는 경우 해당 범위 변수의 형식입니다. 예제에서

    Dim custNames = From c In Customers
                    Select c.Name
    

    쿼리 결과는 요소 형식이 .인 컬렉션 형식 String이 됩니다. 여러 범위 변수가 범위에 있는 경우 범위 R 의 모든 범위 변수를 필드로 Key 포함하는 익명 형식입니다. 예제에서는 다음을 수행합니다.

    Dim custNames = From c In Customers, o In c.Orders 
                    Select Name = c.Name, ProductName = o.ProductName
    

    쿼리 결과는 형식의 읽기 전용 속성과 형식의 읽기 전용 속성이 있는 NameProductName 익명 형식의 요소 형식이 있는 컬렉션 형식 StringString입니다.

    쿼리 식 내에서 범위 변수를 포함하도록 생성된 익명 형식은 투명합니다. 즉, 범위 변수는 항상 정규화 없이 사용할 수 있습니다. 예를 들어 이전 예제에서 범위 변수는 co 입력 컬렉션의 요소 형식이 무명 형식인 경우에도 쿼리 연산자의 한정 Select 없이 액세스할 수 있습니다.

  • 이 형식 CX 은 요소 형식이 일부 X형식인 입력 컬렉션 형식이 아니라 컬렉션 형식을 나타냅니다.

쿼리 가능한 컬렉션 형식은 기본 설정 순서대로 다음 조건 중 하나를 충족해야 합니다.

  • 준수 Select 메서드를 정의해야 합니다.

  • 다음 방법 중 하나가 있어야 합니다.

    Function AsEnumerable() As CT
    Function AsQueryable() As CT
    

    쿼리 가능한 컬렉션을 가져오기 위해 호출할 수 있습니다. 두 메서드가 모두 제공되는 AsQueryableAsEnumerable경우 .

  • 메서드가 있어야 합니다.

    Function Cast(Of T)() As CT
    

    쿼리 가능한 컬렉션을 생성하기 위해 범위 변수의 형식으로 호출할 수 있습니다.

컬렉션의 요소 형식 확인은 실제 메서드 호출과 독립적으로 발생하므로 특정 메서드의 적용 가능성을 확인할 수 없습니다. 따라서 잘 알려진 메서드와 일치하는 인스턴스 메서드가 있는 경우 컬렉션의 요소 형식을 결정할 때 잘 알려진 메서드와 일치하는 확장 메서드는 무시됩니다.

쿼리 연산자 변환은 식에서 쿼리 연산자가 발생하는 순서대로 수행됩니다. 모든 컬렉션 개체가 적어도 쿼리 연산자를 지원 Select 해야 하지만 컬렉션 개체가 모든 쿼리 연산자에 필요한 모든 메서드를 구현할 필요는 없습니다. 필요한 메서드가 없으면 컴파일 시간 오류가 발생합니다. 잘 알려진 메서드 이름을 바인딩하는 경우 섀도킹 의미 체계는 여전히 적용되지만 인터페이스 및 확장 메서드 바인딩에서 여러 상속을 위해 메서드가 아닌 메서드는 무시됩니다. 다음은 그 예입니다.

Class Q1
    Public Function [Select](selector As Func(Of Integer, Integer)) As Q1
    End Function
End Class

Class Q2
    Inherits Q1

    Public [Select] As Integer
End Class

Module Test
    Sub Main()
        Dim qs As New Q2()

        ' Error: Q2.Select still hides Q1.Select
        Dim zs = From q In qs Select q
    End Sub
End Module

기본 쿼리 인덱서

요소 형식이 T 기본 속성이고 아직 기본 속성이 없는 모든 쿼리 가능한 컬렉션 형식은 다음 일반 형식의 기본 속성으로 간주됩니다.

Public ReadOnly Default Property Item(index As Integer) As T
    Get
        Return Me.ElementAtOrDefault(index)
    End Get
End Property

기본 속성은 기본 속성 액세스 구문을 사용하여 참조할 수 있습니다. 기본 속성을 이름으로 참조할 수 없습니다. 다음은 그 예입니다.

Dim customers As IEnumerable(Of Customer) = ...
Dim customerThree = customers(2)

' Error, no such property
Dim customerFour = customers.Item(4)

컬렉션 형식에 멤버가 ElementAtOrDefault 없으면 컴파일 시간 오류가 발생합니다.

쿼리 연산자에서

From 쿼리 연산자는 쿼리할 컬렉션의 개별 멤버를 나타내는 컬렉션 범위 변수를 소개합니다.

FromQueryOperator
    : LineTerminator? 'From' LineTerminator? CollectionRangeVariableDeclarationList
    ;

예를 들어 쿼리 식은 다음과 같습니다.

From c As Customer In Customers ...

은 다음과 같다고 생각할 수 있습니다.

For Each c As Customer In Customers
        ...
Next c

쿼리 연산자가 From 여러 컬렉션 범위 변수를 선언하거나 쿼리 식의 첫 번째 From 쿼리 연산자가 아닌 경우 각 새 컬렉션 범위 변수는 기존 범위 변수 집합에 교차 조 인됩니다. 그 결과 조인된 컬렉션에 있는 모든 요소의 교차곱에 대해 쿼리가 평가됩니다. 예를 들어 식은 다음과 같습니다.

From c In Customers _
From e In Employees _
...

는 다음과 같다고 생각할 수 있습니다.

For Each c In Customers
    For Each e In Employees
            ...
    Next e
Next c

은 다음과 정확히 동일합니다.

From c In Customers, e In Employees ...

이전 쿼리 연산자에 도입된 범위 변수는 이후 From 쿼리 연산자에서 사용할 수 있습니다. 예를 들어 다음 쿼리 식에서 두 번째 From 쿼리 연산자는 첫 번째 범위 변수의 값을 참조합니다.

From c As Customer In Customers _
From o As Order In c.Orders _
Select c.Name, o

쿼리 연산자 From 또는 여러 쿼리 연산자의 여러 From 범위 변수는 컬렉션 형식에 다음 메서드 중 하나 또는 둘 다를 포함하는 경우에만 지원됩니다.

Function SelectMany(selector As Func(Of T, CR)) As CR
Function SelectMany(selector As Func(Of T, CS), _
                          resultsSelector As Func(Of T, S, R)) As CR

코드

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs, y In ys ...

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = _
    xs.SelectMany( _
        Function(x As Integer) ys, _
        Function(x As Integer, y As Integer) New With {x, y})...

메모. From 은 예약된 단어가 아닙니다.

조인 쿼리 연산자

Join 쿼리 연산자는 기존 범위 변수를 새 컬렉션 범위 변수와 조인하여 요소가 같음 식에 따라 함께 조인된 단일 컬렉션을 생성합니다.

JoinQueryOperator
    : LineTerminator? 'Join' LineTerminator? CollectionRangeVariableDeclaration
      JoinOrGroupJoinQueryOperator? LineTerminator? 'On' LineTerminator? JoinConditionList
    ;

JoinConditionList
    : JoinCondition ( 'And' LineTerminator? JoinCondition )*
    ;

JoinCondition
    : Expression 'Equals' LineTerminator? Expression
    ;

다음은 그 예입니다.

Dim customersAndOrders = _
    From cust In Customers _
    Join ord In Orders On cust.ID Equals ord.CustomerID

같음 식은 정규 같음 식보다 더 제한됩니다.

  • 두 식 모두 값으로 분류되어야 합니다.

  • 두 식 모두 하나 이상의 범위 변수를 참조해야 합니다.

  • 조인 쿼리 연산자에 선언된 범위 변수는 식 중 하나에서 참조해야 하며 해당 식은 다른 범위 변수를 참조해서는 안 됩니다.

두 식의 형식이 정확히 동일한 형식이 아닌 경우

  • 두 형식에 대해 같음 연산자가 정의된 경우 두 식 모두 암시적으로 변환할 수 있으며 변환할 수 없는 Object경우 두 식을 해당 형식으로 변환합니다.

  • 그렇지 않은 경우 두 식을 암시적으로 변환할 수 있는 주요 형식이 있는 경우 두 식을 해당 형식으로 변환합니다.

  • 그렇지 않으면 컴파일 시간 오류가 발생합니다.

식은 효율성을 위해 같음 연산자를 사용하는 대신 해시 값(즉, 호출 GetHashCode())을 사용하여 비교됩니다. 쿼리 연산자는 Join 동일한 연산자에서 여러 조인 또는 같음 조건을 수행할 수 있습니다. Join 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function Join(inner As CS, _
                  outerSelector As Func(Of T, K), _
                  innerSelector As Func(Of S, K), _
                  resultSelector As Func(Of T, S, R)) As CR

코드

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs _
            Join y In ys On x Equals y _
            ...

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = _
    xs.Join( _
        ys, _
        Function(x As Integer) x, _
        Function(y As Integer) y, _
        Function(x As Integer, y As Integer) New With {x, y})...

참고.JoinOn 예약 Equals 단어는 아닙니다.

쿼리 연산자 허용

Let 쿼리 연산자는 식 범위 변수를 도입합니다. 이렇게 하면 이후 쿼리 연산자에서 여러 번 사용되는 중간 값을 한 번 계산할 수 있습니다.

LetQueryOperator
    : LineTerminator? 'Let' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

다음은 그 예입니다.

Dim taxedPrices = _
    From o In Orders _
    Let tax = o.Price * 0.088 _
    Where tax > 3.50 _
    Select o.Price, tax, total = o.Price + tax

는 다음과 같다고 생각할 수 있습니다.

For Each o In Orders
    Dim tax = o.Price * 0.088
    ...
Next o

Let 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function Select(selector As Func(Of T, R)) As CR

코드

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Let y = x * 10 _
            ...

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim zs = _
    xs.Select(Function(x As Integer) New With {x, .y = x * 10})...

쿼리 연산자 선택

Select 쿼리 연산자는 식 범위 변수를 도입한다는 측면에서 쿼리 연산자처럼 Let 되지만 쿼리 Select 연산자는 현재 사용 가능한 범위 변수를 추가하지 않고 숨깁니다. 또한 쿼리 연산자에 의해 Select 도입된 식 범위 변수의 형식은 항상 지역 변수 형식 유추 규칙을 사용하여 유추됩니다. 명시적 형식을 지정할 수 없으며 형식을 유추할 수 없는 경우 컴파일 시간 오류가 발생합니다.

SelectQueryOperator
    : LineTerminator? 'Select' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

예를 들어 쿼리에서 다음을 수행합니다.

Dim smiths = _
    From cust In Customers _
    Select name = cust.name _
    Where name.EndsWith("Smith")

쿼리 연산자는 Where 연산자가 name 도입한 범위 변수에 Select 만 액세스할 수 있습니다. 연산자가 Where 참조 cust하려고 하면 컴파일 시간 오류가 발생했습니다.

쿼리 연산자는 범위 변수 Select 의 이름을 명시적으로 지정하는 대신 익명 형식 개체 생성 식과 동일한 규칙을 사용하여 범위 변수의 이름을 유추할 수 있습니다. 다음은 그 예입니다.

Dim custAndOrderNames = _
      From cust In Customers, ord In cust.Orders _
      Select cust.name, ord.ProductName _
        Where name.EndsWith("Smith")

범위 변수의 이름이 제공되지 않고 이름을 유추할 수 없는 경우 컴파일 시간 오류가 발생합니다. Select 쿼리 연산자에 단일 식만 포함된 경우 해당 범위 변수의 이름을 유추할 수 없지만 범위 변수는 이름이 없는 경우 오류가 발생하지 않습니다. 다음은 그 예입니다.

Dim custAndOrderNames = _
      From cust In Customers, ord In cust.Orders _
      Select cust.Name & " bought " & ord.ProductName _
        Take 10

범위 변수에 Select 이름을 할당하는 것과 같음 식 사이에 쿼리 연산자에 모호성이 있는 경우 이름 할당이 선호됩니다. 다음은 그 예입니다.

Dim badCustNames = _
      From c In Customers _
        Let name = "John Smith" _
      Select name = c.Name ' Creates a range variable named "name"


Dim goodCustNames = _
      From c In Customers _
        Let name = "John Smith" _
      Select match = (name = c.Name)

쿼리 연산자의 각 식은 Select 값으로 분류되어야 합니다. Select 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function Select(selector As Func(Of T, R)) As CR

코드

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Select x, y = x * 10 _
            ...

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim zs = _
    xs.Select(Function(x As Integer) New With {x, .y = x * 10})...

고유 쿼리 연산자

Distinct 쿼리 연산자는 요소 형식을 같음으로 비교하여 결정된 대로 컬렉션의 값만 고유 값을 가진 값으로 제한합니다.

DistinctQueryOperator
    : LineTerminator? 'Distinct' LineTerminator?
    ;

예를 들어 쿼리는

Dim distinctCustomerPrice = _
    From cust In Customers, ord In cust.Orders _
    Select cust.Name, ord.Price _
    Distinct

는 고객이 동일한 가격으로 여러 주문을 하더라도 고객 이름과 주문 가격의 각 고유 페어링에 대해 하나의 행만 반환합니다. Distinct 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function Distinct() As CT

코드

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Distinct _
            ...

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim zs = xs.Distinct()...

메모. Distinct 은 예약된 단어가 아닙니다.

Where Query 연산자

Where 쿼리 연산자는 컬렉션의 값을 지정된 조건을 충족하는 값으로 제한합니다.

WhereQueryOperator
    : LineTerminator? 'Where' LineTerminator? BooleanExpression
    ;

Where 쿼리 연산자는 범위 변수 값의 각 집합에 대해 계산되는 부울 식을 사용합니다. 식의 값이 true이면 값이 출력 컬렉션에 나타나고, 그렇지 않으면 값을 건너뜁습니다. 예를 들어 쿼리 식은 다음과 같습니다.

From cust In Customers, ord In Orders _
Where cust.ID = ord.CustomerID _
...

는 중첩된 루프와 동등하다고 생각할 수 있습니다.

For Each cust In Customers
    For Each ord In Orders
            If cust.ID = ord.CustomerID Then
                ...
            End If
    Next ord
Next cust

Where 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function Where(predicate As Func(Of T, B)) As CT

코드

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Where x < 10 _
            ...

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim zs = _
    xs.Where(Function(x As Integer) x < 10)...

메모. Where 은 예약된 단어가 아닙니다.

파티션 쿼리 연산자

PartitionQueryOperator
    : LineTerminator? 'Take' LineTerminator? Expression
    | LineTerminator? 'Take' 'While' LineTerminator? BooleanExpression
    | LineTerminator? 'Skip' LineTerminator? Expression
    | LineTerminator? 'Skip' 'While' LineTerminator? BooleanExpression
    ;

Take 쿼리 연산자는 컬렉션의 첫 번째 n 요소를 생성합니다. 한정자와 함께 While 사용할 경우 연산자는 Take 부울 식을 충족하는 컬렉션의 첫 번째 n 요소를 생성합니다. Skip 연산자는 컬렉션의 첫 번째 n 요소를 건너뛰고 컬렉션의 나머지 부분을 반환합니다. 한정자와 함께 While 사용하는 경우 연산자는 Skip 부울 식을 충족하는 컬렉션의 첫 번째 n 요소를 건너뛰고 나머지 컬렉션을 반환합니다. 또는 Skip 쿼리 연산자의 Take 식은 값으로 분류되어야 합니다.

Take 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function Take(count As N) As CT

Skip 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function Skip(count As N) As CT

Take While 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function TakeWhile(predicate As Func(Of T, B)) As CT

Skip While 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function SkipWhile(predicate As Func(Of T, B)) As CT

코드

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Skip 10 _
            Take 5 _
            Skip While x < 10 _
            Take While x > 5 _
            ...

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim zs = _
    xs.Skip(10). _
        Take(5). _
        SkipWhile(Function(x) x < 10). _
        TakeWhile(Function(x) x > 5)...

메모. Take 예약 Skip 된 단어가 아닙니다.

쿼리 연산자별 순서

Order By 쿼리 연산자는 범위 변수에 표시되는 값을 정렬합니다.

OrderByQueryOperator
    : LineTerminator? 'Order' 'By' LineTerminator? OrderExpressionList
    ;

OrderExpressionList
    : OrderExpression ( Comma OrderExpression )*
    ;

OrderExpression
    : Expression Ordering?
    ;

Ordering
    : 'Ascending' | 'Descending'
    ;

Order By 쿼리 연산자는 반복 변수를 정렬하는 데 사용해야 하는 키 값을 지정하는 식을 사용합니다. 예를 들어 다음 쿼리는 가격을 기준으로 정렬된 제품을 반환합니다.

Dim productsByPrice = _
    From p In Products _
    Order By p.Price _
    Select p.Name

정렬은 더 작은 값이 더 큰 값보다 앞에 오거나 Descending더 큰 값이 작은 값보다 앞에 오는 순서로 Ascending표시될 수 있습니다. 지정하지 않은 경우 순서 지정의 기본값은 .입니다 Ascending. 예를 들어 다음 쿼리는 가장 비싼 제품을 먼저 사용하여 가격을 기준으로 정렬된 제품을 반환합니다.

Dim productsByPriceDesc = _
    From p In Products _
    Order By p.Price Descending _
    Select p.Name

쿼리 연산자는 Order By 순서 지정을 위해 여러 식을 지정할 수 있습니다. 이 경우 컬렉션은 중첩된 방식으로 정렬됩니다. 예를 들어 다음 쿼리는 주별, 각 주 내의 도시 및 각 도시 내의 우편 번호로 고객을 주문합니다.

Dim customersByLocation = _
    From c In Customers _
    Order By c.State, c.City, c.ZIP _
    Select c.Name, c.State, c.City, c.ZIP

쿼리 연산자의 Order By 식은 값으로 분류되어야 합니다. Order By 쿼리 연산자는 컬렉션 형식에 다음 메서드 중 하나 또는 둘 다를 포함하는 경우에만 지원됩니다.

Function OrderBy(keySelector As Func(Of T, K)) As CT
Function OrderByDescending(keySelector As Func(Of T, K)) As CT

반환 형식 CT순서가 지정된 컬렉션이어야 합니다. 정렬된 컬렉션은 메서드 중 하나 또는 둘 다를 포함하는 컬렉션 형식입니다.

Function ThenBy(keySelector As Func(Of T, K)) As CT
Function ThenByDescending(keySelector As Func(Of T, K)) As CT

코드

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Order By x Ascending, x Mod 2 Descending _
            ...

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim zs = _
    xs.OrderBy(Function(x) x).ThenByDescending(Function(x) x Mod 2)...

메모. 쿼리 연산자는 단순히 구문을 특정 쿼리 작업을 구현하는 메서드에 매핑하기 때문에 순서 유지는 언어에 의해 결정되지 않으며 연산자 자체의 구현에 의해 결정됩니다. 이는 사용자 정의 숫자 형식에 대한 더하기 연산자를 오버로드하는 구현이 더하기와 유사한 작업을 수행하지 않을 수 있다는 측면에서 사용자 정의 연산자와 매우 유사합니다. 물론 예측 가능성을 유지하기 위해 사용자 기대와 일치하지 않는 항목을 구현하는 것은 권장되지 않습니다.

메모. Order 예약 By 된 단어가 아닙니다.

쿼리 연산자별 그룹화

쿼리 연산자는 Group By 하나 이상의 식을 기반으로 범위 변수를 범위로 그룹화한 다음 해당 그룹화에 따라 새 범위 변수를 생성합니다.

GroupByQueryOperator
    : LineTerminator? 'Group' ( LineTerminator? ExpressionRangeVariableDeclarationList )?
      LineTerminator? 'By' LineTerminator? ExpressionRangeVariableDeclarationList
      LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

예를 들어 다음 쿼리는 모든 고객을 그룹화한 State다음 각 그룹의 수와 평균 연령을 계산합니다.

Dim averageAges = _
    From cust In Customers _
    Group By cust.State _
    Into Count(), Average(cust.Age)

쿼리 연산자에는 Group By 선택적 Group 절, By 절 및 절의 세 가지 절이 Into 있습니다. 절은 GroupSelect 절이 아닌 By 절에서 Into 사용할 수 있는 범위 변수에만 영향을 줍니다. 다음은 그 예입니다.

Dim averageAges = _
    From cust In Customers _
    Group cust.Age By cust.State _
    Into Count(), Average(Age)

이 절은 By 그룹화 작업에서 키 값으로 사용되는 식 범위 변수를 선언합니다. 절은 Into 절에 의해 형성된 각 그룹에 대한 집계를 계산하는 식 범위 변수의 선언을 By 허용합니다. Into 절 내에서 식 범위 변수는 집계 함수의 메서드 호출인 식만 할당할 수 있습니다. 집계 함수는 다음 메서드 중 하나처럼 보이는 그룹의 컬렉션 형식(원래 컬렉션의 컬렉션 형식과 동일하지 않을 수도 있음)에 대한 함수입니다.

Function _name_() As _type_
Function _name_(selector As Func(Of T, R)) As R

집계 함수가 대리자 인수를 사용하는 경우 호출 식에는 값으로 분류해야 하는 인수 식이 있을 수 있습니다. 인수 식은 범위에 있는 범위 변수를 사용할 수 있습니다. 집계 함수 호출 내에서 해당 범위 변수는 컬렉션의 모든 값이 아니라 형성되는 그룹의 값을 나타냅니다. 예를 들어 이 섹션 Average 의 원래 예제에서 함수는 모든 고객이 함께 사용하는 것이 아니라 주별 고객 연령의 평균을 계산합니다.

모든 컬렉션 형식은 매개 변수를 사용하지 않고 단순히 그룹을 반환하는 집계 함수 Group 를 정의한 것으로 간주됩니다. 컬렉션 형식이 제공할 수 있는 다른 표준 집계 함수는 다음과 같습니다.

CountLongCount- 그룹의 요소 개수 또는 부울 식을 충족하는 그룹의 요소 수를 반환합니다. Count 컬렉션 LongCount 형식에 메서드 중 하나가 포함된 경우에만 지원됩니다.

Function Count() As N
Function Count(selector As Func(Of T, B)) As N
Function LongCount() As N
Function LongCount(selector As Func(Of T, B)) As N

Sum- 그룹의 모든 요소에서 식의 합계를 반환합니다. Sum 은 컬렉션 형식에 메서드 중 하나가 포함된 경우에만 지원됩니다.

Function Sum() As N
Function Sum(selector As Func(Of T, N)) As N

Min 는 그룹의 모든 요소에서 식의 최소값을 반환합니다. Min 은 컬렉션 형식에 메서드 중 하나가 포함된 경우에만 지원됩니다.

Function Min() As N
Function Min(selector As Func(Of T, N)) As N

Max- 그룹의 모든 요소에서 식의 최대값을 반환합니다. Max 은 컬렉션 형식에 메서드 중 하나가 포함된 경우에만 지원됩니다.

Function Max() As N
Function Max(selector As Func(Of T, N)) As N

Average- 그룹의 모든 요소에 대한 식의 평균을 반환합니다. Average 은 컬렉션 형식에 메서드 중 하나가 포함된 경우에만 지원됩니다.

Function Average() As N
Function Average(selector As Func(Of T, N)) As N

Any- 그룹에 멤버가 포함되어 있는지 또는 그룹의 모든 요소에 대해 부울 식이 true인지 여부를 결정합니다. Any 는 부울 식에서 사용할 수 있는 값을 반환하며 컬렉션 형식에 메서드 중 하나가 포함된 경우에만 지원됩니다.

Function Any() As B
Function Any(predicate As Func(Of T, B)) As B

All- 그룹의 모든 요소에 대해 부울 식이 true인지 여부를 결정합니다. All 는 부울 식에서 사용할 수 있는 값을 반환하며 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function All(predicate As Func(Of T, B)) As B

쿼리 연산자 Group By 후에는 범위의 이전 범위 변수가 숨겨지고 and Into 절에 의해 도입된 범위 변수를 By 사용할 수 있습니다. Group By 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function GroupBy(keySelector As Func(Of T, K), _
                      resultSelector As Func(Of K, CT, R)) As CR

절의 Group 범위 변수 선언은 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function GroupBy(keySelector As Func(Of T, K), _
                      elementSelector As Func(Of T, S), _
                      resultSelector As Func(Of K, CS, R)) As CR

코드

Dim xs() As Integer = ...
Dim zs = From x In xs _
            Group y = x * 10, z = x / 10 By evenOdd = x Mod 2 _
            Into Sum(y), Average(z) _
            ...

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim zs = _
    xs.GroupBy( _
        Function(x As Integer) x Mod 2, _
        Function(x As Integer) New With {.y = x * 10, .z = x / 10}, _
        Function(evenOdd, group) New With { _
            evenOdd, _
            .Sum = group.Sum(Function(e) e.y), _
            .Average = group.Average(Function(e) e.z)})...

참고.GroupBy 예약 Into 단어는 아닙니다.

집계 쿼리 연산자

Aggregate 쿼리 연산자는 이미 형성된 그룹에 대한 집계를 허용한다는 점을 제외하고 연산자로 유사한 함수 Group By 를 수행합니다. 그룹이 이미 구성 Into 되었으므로 쿼리 연산자의 Aggregate 절은 범위의 범위 변수를 숨기지 않습니다(이런 방식으로 LetAggregate 는 더 비슷하고 Group BySelect더 비슷합니다).

AggregateQueryOperator
    : LineTerminator? 'Aggregate' LineTerminator? CollectionRangeVariableDeclaration QueryOperator*
      LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

예를 들어 다음 쿼리는 워싱턴에 있는 고객이 주문한 모든 주문의 합계를 집계합니다.

Dim orderTotals = _
    From cust In Customers _
    Where cust.State = "WA" _
    Aggregate order In cust.Orders _
    Into Sum(order.Total)

이 쿼리의 결과는 요소 형식이 형식화된 속성과 형식화된 Customer 속성 custSumInteger이 있는 익명 형식인 컬렉션입니다.

달리Group By, 추가 쿼리 연산자는 절과 Into 절 사이에 Aggregate 배치할 수 있습니다. Aggregate 절과 절의 Into 끝 사이에는 절에 의해 선언된 변수를 포함하여 범위의 모든 범위 변수를 Aggregate 사용할 수 있습니다. 예를 들어 다음 쿼리는 2006년 이전에 워싱턴에 있는 고객이 주문한 모든 주문의 합계를 집계합니다.

Dim orderTotals = _
    From cust In Customers _
    Where cust.State = "WA" _
    Aggregate order In cust.Orders _
    Where order.Date <= #01/01/2006# _
    Into Sum = Sum(order.Total)

연산자를 Aggregate 사용하여 쿼리 식을 시작할 수도 있습니다. 이 경우 쿼리 식의 결과는 절에 의해 계산되는 단일 값이 Into 됩니다. 예를 들어 다음 쿼리는 2006년 1월 1일 이전의 모든 주문 합계의 합계를 계산합니다.

Dim ordersTotal = _
    Aggregate order In Orders _
    Where order.Date <= #01/01/2006# _
    Into Sum(order.Total)

쿼리 결과는 단일 Integer 값입니다. Aggregate 쿼리 연산자는 항상 사용할 수 있습니다(식이 유효하려면 집계 함수도 사용할 수 있어야 하지만). 코드

Dim xs() As Integer = ...
Dim zs = _
    Aggregate x In xs _
    Where x < 5 _
    Into Sum()

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim zs = _
    xs.Where(Function(x) x < 5).Sum()

메모.  Aggregate 예약 Into 된 단어가 아닙니다.

그룹 조인 쿼리 연산자

Group Join 쿼리 연산자는 쿼리 Group By 연산자와 쿼리 연산자의 Join 함수를 단일 연산자에 결합합니다. Group Join 조인의 왼쪽에 있는 특정 요소와 일치하는 조인의 오른쪽에 있는 모든 요소를 그룹화하여 요소에서 추출된 일치하는 키를 기반으로 두 컬렉션을 조인합니다. 따라서 연산자는 계층적 결과 집합을 생성합니다.

GroupJoinQueryOperator
    : LineTerminator? 'Group' 'Join' LineTerminator? CollectionRangeVariableDeclaration
      JoinOrGroupJoinQueryOperator? LineTerminator? 'On' LineTerminator? JoinConditionList
      LineTerminator? 'Into' LineTerminator? ExpressionRangeVariableDeclarationList
    ;

예를 들어 다음 쿼리는 단일 고객의 이름, 모든 주문 그룹 및 모든 주문의 총 금액을 포함하는 요소를 생성합니다.

Dim custsWithOrders = _
    From cust In Customers _
    Group Join order In Orders On cust.ID Equals order.CustomerID _ 
    Into Orders = Group, OrdersTotal = Sum(order.Total) _
    Select cust.Name, Orders, OrdersTotal

쿼리의 결과는 요소 형식이 세 가지 Name속성이 있는 무명 형식인 컬렉션입니다. 즉, 로 String형식화되고, Orders 요소 형식 Order이 컬렉션으로 입력되고 OrdersTotal, 로 Integer입력됩니다. Group Join 쿼리 연산자는 컬렉션 형식에 메서드가 포함된 경우에만 지원됩니다.

Function GroupJoin(inner As CS, _
                         outerSelector As Func(Of T, K), _
                         innerSelector As Func(Of S, K), _
                         resultSelector As Func(Of T, CS, R)) As CR

코드

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = From x In xs _
            Group Join y in ys On x Equals y _
            Into g = Group _
            ...

는 일반적으로 다음으로 변환됩니다.

Dim xs() As Integer = ...
Dim ys() As Integer = ...
Dim zs = _
    xs.GroupJoin( _
        ys, _
        Function(x As Integer) x, _
        Function(y As Integer) y, _
        Function(x, group) New With {x, .g = group})...

참고.GroupJoin 예약 Into 단어는 아닙니다.

조건식

조건 If 식은 식을 테스트하고 값을 반환합니다.

ConditionalExpression
    : 'If' OpenParenthesis BooleanExpression Comma Expression Comma Expression CloseParenthesis
    | 'If' OpenParenthesis Expression Comma Expression CloseParenthesis
    ;

IIF 그러나 런타임 함수와 달리 조건식은 필요한 경우에만 해당 피연산자를 평가합니다. 따라서 예를 들어 값 cNothing이 .인 경우 식 If(c Is Nothing, c.Name, "Unknown") 에서 예외를 throw하지 않습니다. 조건식에는 두 개의 피연산자를 사용하는 형식과 3개의 피연산자를 사용하는 형식이 있습니다.

세 개의 피연산자를 제공하는 경우 세 식은 모두 값으로 분류되어야 하며 첫 번째 피연산자는 부울 식이어야 합니다. 식의 결과가 true이면 두 번째 식은 연산자의 결과가 되고, 그렇지 않으면 세 번째 식은 연산자의 결과가 됩니다. 식의 결과 형식은 두 번째 식과 세 번째 식의 형식 사이의 주요 형식입니다. 주요 형식이 없으면 컴파일 시간 오류가 발생합니다.

두 피연산자를 제공하는 경우 두 피연산자는 모두 값으로 분류되어야 하며 첫 번째 피연산자는 참조 형식 또는 nullable 값 형식이어야 합니다. If(x, y) 식은 두 가지 예외를 제외하고 식If(x IsNot Nothing, x, y)인 것처럼 평가됩니다. 첫째, 첫 번째 식은 한 번만 계산되고 두 번째 피연산자의 형식이 null을 허용하지 않는 값 형식이고 첫 번째 피연산자의 형식이 ? 면 식의 결과 형식에 대한 기준 형식을 결정할 때 첫 번째 피연산자의 형식에서 제거됩니다. 다음은 그 예입니다.

Module Test
    Sub Main()
        Dim x?, y As Integer
        Dim a?, b As Long

        a = If(x, a)        ' Result type: Long?
        y = If(x, 0)        ' Result type: Integer
    End Sub
End Module

식의 두 형태에서 피연산자인 Nothing경우 해당 형식은 주요 형식을 결정하는 데 사용되지 않습니다. 식 If(<expression>, Nothing, Nothing)의 경우 주 형식은 다음과 같은 것으로 Object간주됩니다.

XML 리터럴 식

XML 리터럴 식은 XML(eXtensible Markup Language) 1.0 값을 나타냅니다.

XMLLiteralExpression
    : XMLDocument
    | XMLElement
    | XMLProcessingInstruction
    | XMLComment
    | XMLCDATASection
    ;

XML 리터럴 식의 결과는 네임스페이스의 형식 System.Xml.Linq 중 하나로 형식화된 값입니다. 해당 네임스페이스의 형식을 사용할 수 없는 경우 XML 리터럴 식으로 인해 컴파일 시간 오류가 발생합니다. 값은 XML 리터럴 식에서 변환된 생성자 호출을 통해 생성됩니다. 예를 들어 코드는 다음과 같습니다.

Dim book As System.Xml.Linq.XElement = _
    <book title="My book"></book>

는 코드와 거의 동일합니다.

Dim book As System.Xml.Linq.XElement = _
    New System.Xml.Linq.XElement( _
        "book", _
        New System.Xml.Linq.XAttribute("title", "My book"))

XML 리터럴 식은 XML 문서, XML 요소, XML 처리 명령, XML 주석 또는 CDATA 섹션의 형식을 사용할 수 있습니다.

메모. 이 사양에는 Visual Basic 언어의 동작을 설명하기에 충분한 XML 설명만 포함되어 있습니다. XML에 대한 자세한 내용은 .에서 http://www.w3.org/TR/REC-xml/찾을 수 있습니다.

어휘 규칙

XMLCharacter
    : '<Unicode tab character (0x0009)>'
    | '<Unicode linefeed character (0x000A)>'
    | '<Unicode carriage return character (0x000D)>'
    | '<Unicode characters 0x0020 - 0xD7FF>'
    | '<Unicode characters 0xE000 - 0xFFFD>'
    | '<Unicode characters 0x10000 - 0x10FFFF>'
    ;

XMLString
    : XMLCharacter+
    ;

XMLWhitespace
    : XMLWhitespaceCharacter+
    ;

XMLWhitespaceCharacter
    : '<Unicode carriage return character (0x000D)>'
    | '<Unicode linefeed character (0x000A)>'
    | '<Unicode space character (0x0020)>'
    | '<Unicode tab character (0x0009)>'
    ;

XMLNameCharacter
    : XMLLetter
    | XMLDigit
    | '.'
    | '-'
    | '_'
    | ':'
    | XMLCombiningCharacter
    | XMLExtender
    ;

XMLNameStartCharacter
    : XMLLetter
    | '_'
    | ':'
    ;

XMLName
    : XMLNameStartCharacter XMLNameCharacter*
    ;

XMLLetter
    : '<Unicode character as defined in the Letter production of the XML 1.0 specification>'
    ;

XMLDigit
    : '<Unicode character as defined in the Digit production of the XML 1.0 specification>'
    ;

XMLCombiningCharacter
    : '<Unicode character as defined in the CombiningChar production of the XML 1.0 specification>'
    ;

XMLExtender
    : '<Unicode character as defined in the Extender production of the XML 1.0 specification>'
    ;

XML 리터럴 식은 일반 Visual Basic 코드의 어휘 규칙 대신 XML의 어휘 규칙을 사용하여 해석됩니다. 일반적으로 두 규칙 집합은 다음과 같은 방식으로 다릅니다.

  • 공백은 XML에서 중요합니다. 따라서 XML 리터럴 식의 문법은 공백이 허용되는 위치를 명시적으로 나타냅니다. 공백은 요소 내의 문자 데이터 컨텍스트에서 발생하는 경우를 제외하고 보존되지 않습니다. 다음은 그 예입니다.

    ' The following element preserves no whitespace
    Dim e1 = _
        <customer>
            <name>Bob</>
        </>
    
    ' The following element preserves all of the whitespace
    Dim e2 = _
        <customer>
            Bob
        </>
    
  • XML 줄 끝 공백은 XML 사양에 따라 정규화됩니다.

  • XML은 대/소문자를 구분합니다. 키워드는 대/소문자를 정확히 일치시켜야 합니다. 그렇지 않으면 컴파일 시간 오류가 발생합니다.

  • 줄 종결자는 XML의 공백으로 간주됩니다. 따라서 XML 리터럴 식에는 줄 연속 문자가 필요하지 않습니다.

  • XML은 전체 너비 문자를 허용하지 않습니다. 전체 너비 문자를 사용하는 경우 컴파일 시간 오류가 발생합니다.

포함된 식

XML 리터럴 식에는 포함된 식이 포함될 수 있습니다. 포함된 식은 포함된 식의 위치에서 하나 이상의 값을 채우는 데 계산되고 사용되는 Visual Basic 식입니다.

XMLEmbeddedExpression
    : '<' '%' '=' LineTerminator? Expression LineTerminator? '%' '>'
    ;

예를 들어 다음 코드는 문자열 John Smith 을 XML 요소의 값으로 배치합니다.

Dim name as String = "John Smith"
Dim element As System.Xml.Linq.XElement = <customer><%= name %></customer>

식은 여러 컨텍스트에 포함될 수 있습니다. 예를 들어 다음 코드는 다음과 같은 요소를 customer생성합니다.

Dim name As String = "customer"
Dim element As System.Xml.Linq.XElement = <<%= name %>>John Smith</>

포함된 식을 사용할 수 있는 각 컨텍스트는 허용되는 형식을 지정합니다. 포함된 식의 식 부분 컨텍스트 내에서 Visual Basic 코드에 대한 일반 어휘 규칙이 계속 적용되므로 예를 들어 줄 연속을 사용해야 합니다.

' Visual Basic expression uses line continuation, XML does not
Dim element As System.Xml.Linq.XElement = _
    <<%= name & _
          name %>>John 
                     Smith</>

XML 문서

XMLDocument
    : XMLDocumentPrologue XMLMisc* XMLDocumentBody XMLMisc*
    ;

XMLDocumentPrologue
    : '<' '?' 'xml' XMLVersion XMLEncoding? XMLStandalone? XMLWhitespace? '?' '>'
    ;

XMLVersion
    : XMLWhitespace 'version' XMLWhitespace? '=' XMLWhitespace? XMLVersionNumberValue
    ;

XMLVersionNumberValue
    : SingleQuoteCharacter '1' '.' '0' SingleQuoteCharacter
    | DoubleQuoteCharacter '1' '.' '0' DoubleQuoteCharacter
    ;

XMLEncoding
    : XMLWhitespace 'encoding' XMLWhitespace? '=' XMLWhitespace? XMLEncodingNameValue
    ;

XMLEncodingNameValue
    : SingleQuoteCharacter XMLEncodingName SingleQuoteCharacter
    | DoubleQuoteCharacter XMLEncodingName DoubleQuoteCharacter
    ;

XMLEncodingName
    : XMLLatinAlphaCharacter XMLEncodingNameCharacter*
    ;

XMLEncodingNameCharacter
    : XMLUnderscoreCharacter
    | XMLLatinAlphaCharacter
    | XMLNumericCharacter
    | XMLPeriodCharacter
    | XMLDashCharacter
    ;

XMLLatinAlphaCharacter
    : '<Unicode Latin alphabetic character (0x0041-0x005a, 0x0061-0x007a)>'
    ;

XMLNumericCharacter
    : '<Unicode digit character (0x0030-0x0039)>'
    ;

XMLHexNumericCharacter
    : XMLNumericCharacter
    | '<Unicode Latin hex alphabetic character (0x0041-0x0046, 0x0061-0x0066)>'
    ;

XMLPeriodCharacter
    : '<Unicode period character (0x002e)>'
    ;

XMLUnderscoreCharacter
    : '<Unicode underscore character (0x005f)>'
    ;

XMLDashCharacter
    : '<Unicode dash character (0x002d)>'
    ;

XMLStandalone
    : XMLWhitespace 'standalone' XMLWhitespace? '=' XMLWhitespace? XMLYesNoValue
    ;

XMLYesNoValue
    : SingleQuoteCharacter XMLYesNo SingleQuoteCharacter
    | DoubleQuoteCharacter XMLYesNo DoubleQuoteCharacter
    ;

XMLYesNo
    : 'yes'
    | 'no'
    ;

XMLMisc
    : XMLComment
    | XMLProcessingInstruction
    | XMLWhitespace
    ;

XMLDocumentBody
    : XMLElement
    | XMLEmbeddedExpression
    ;

XML 문서를 사용하면 값이 다음과 같이 System.Xml.Linq.XDocument입력됩니다. XML 1.0 사양과 달리 XML 리터럴 식의 XML 문서는 XML 문서 프롤로그를 지정해야 합니다. XML 문서 프롤로그가 없는 XML 리터럴 식은 개별 엔터티로 해석됩니다. 다음은 그 예입니다.

Dim doc As System.Xml.Linq.XDocument = _
    <?xml version="1.0"?>
    <?instruction?>
    <customer>Bob</>

Dim pi As System.Xml.Linq.XProcessingInstruction = _
    <?instruction?>

XML 문서에는 형식이 모든 형식일 수 있는 포함된 식이 포함될 수 있습니다. 그러나 런타임에 개체가 생성자의 요구 사항을 XDocument 충족해야 합니다. 그렇지 않으면 런타임 오류가 발생합니다.

일반 XML과 달리 XML 문서 식은 DTD(문서 형식 선언)를 지원하지 않습니다. 또한 Xml 리터럴 식의 인코딩은 항상 원본 파일 자체의 인코딩과 동일하므로 인코딩 특성(제공된 경우)은 무시됩니다.

메모. 인코딩 특성은 무시되지만 소스 코드에 유효한 Xml 1.0 문서를 포함하는 기능을 유지하기 위해 유효한 특성입니다.

XML 요소

XMLElement
    : XMLEmptyElement
    | XMLElementStart XMLContent XMLElementEnd
    ;

XMLEmptyElement
    : '<' XMLQualifiedNameOrExpression XMLAttribute* XMLWhitespace? '/' '>'
    ;

XMLElementStart
    : '<' XMLQualifiedNameOrExpression XMLAttribute* XMLWhitespace? '>'
    ;

XMLElementEnd
    : '<' '/' '>'
    | '<' '/' XMLQualifiedName XMLWhitespace? '>'
    ;

XMLContent
    : XMLCharacterData? ( XMLNestedContent XMLCharacterData? )+
    ;

XMLCharacterData
    : '<Any XMLCharacterDataString that does not contain the string "]]>">'
    ;

XMLCharacterDataString
    : '<Any Unicode character except < or &>'+
    ;

XMLNestedContent
    : XMLElement
    | XMLReference
    | XMLCDATASection
    | XMLProcessingInstruction
    | XMLComment
    | XMLEmbeddedExpression
    ;

XMLAttribute
    : XMLWhitespace XMLAttributeName XMLWhitespace? '=' XMLWhitespace? XMLAttributeValue
    | XMLWhitespace XMLEmbeddedExpression
    ;

XMLAttributeName
    : XMLQualifiedNameOrExpression
    | XMLNamespaceAttributeName
    ;

XMLAttributeValue
    : DoubleQuoteCharacter XMLAttributeDoubleQuoteValueCharacter* DoubleQuoteCharacter
    | SingleQuoteCharacter XMLAttributeSingleQuoteValueCharacter* SingleQuoteCharacter
    | XMLEmbeddedExpression
    ;

XMLAttributeDoubleQuoteValueCharacter
    : '<Any XMLCharacter except <, &, or DoubleQuoteCharacter>'
    | XMLReference
    ;

XMLAttributeSingleQuoteValueCharacter
    : '<Any XMLCharacter except <, &, or SingleQuoteCharacter>'
    | XMLReference
    ;

XMLReference
    : XMLEntityReference
    | XMLCharacterReference
    ;

XMLEntityReference
    : '&' XMLEntityName ';'
    ;

XMLEntityName
    : 'lt' | 'gt' | 'amp' | 'apos' | 'quot'
    ;

XMLCharacterReference
    : '&' '#' XMLNumericCharacter+ ';'
    | '&' '#' 'x' XMLHexNumericCharacter+ ';'
    ;

XML 요소를 사용하면 값이 .로 System.Xml.Linq.XElement형식화됩니다. 일반 XML과 달리 XML 요소는 닫는 태그의 이름을 생략할 수 있으며 현재 가장 중첩된 요소는 닫힙니다. 다음은 그 예입니다.

Dim name = <name>Bob</>

XML 요소의 특성 선언은 값이 .로 System.Xml.Linq.XAttribute형식화됩니다. 특성 값은 XML 사양에 따라 정규화됩니다. 특성 값이 Nothing 면 특성이 만들어지지 않으므로 특성 값 식을 검사 Nothing할 필요가 없습니다. 다음은 그 예입니다.

Dim expr = Nothing

' Throws null argument exception
Dim direct = New System.Xml.Linq.XElement( _
    "Name", _
    New System.Xml.Linq.XAttribute("Length", expr))

' Doesn't throw exception, the result is <Name/>
Dim literal = <Name Length=<%= expr %>/>

XML 요소 및 특성은 다음 위치에 중첩된 식을 포함할 수 있습니다.

요소의 이름입니다. 이 경우 포함된 식은 암시적으로 변환 가능한 System.Xml.Linq.XName형식의 값이어야 합니다. 다음은 그 예입니다.

Dim name = <<%= "name" %>>Bob</>

요소의 특성 이름입니다. 이 경우 포함된 식은 암시적으로 변환 가능한 System.Xml.Linq.XName형식의 값이어야 합니다. 다음은 그 예입니다.

Dim name = <name <%= "length" %>="3">Bob</>

요소의 특성 값입니다. 이 경우 포함된 식은 모든 형식의 값이 될 수 있습니다. 다음은 그 예입니다.

Dim name = <name length=<%= 3 %>>Bob</>

요소의 특성입니다. 이 경우 포함된 식은 모든 형식의 값이 될 수 있습니다. 다음은 그 예입니다.

Dim name = <name <%= new XAttribute("length", 3) %>>Bob</>

요소의 내용입니다. 이 경우 포함된 식은 모든 형식의 값이 될 수 있습니다. 다음은 그 예입니다.

Dim name = <name><%= "Bob" %></>

포함된 식의 형식이 Object()면 배열이 생성자에 매개 변수 XElement 로 전달됩니다.

XML 네임스페이스

XML 네임스페이스 1.0 사양에 정의된 대로 XML 요소에는 XML 네임스페이스 선언이 포함될 수 있습니다.

XMLNamespaceAttributeName
    : XMLPrefixedNamespaceAttributeName
    | XMLDefaultNamespaceAttributeName
    ;

XMLPrefixedNamespaceAttributeName
    : 'xmlns' ':' XMLNamespaceName
    ;

XMLDefaultNamespaceAttributeName
    : 'xmlns'
    ;

XMLNamespaceName
    : XMLNamespaceNameStartCharacter XMLNamespaceNameCharacter*
    ;

XMLNamespaceNameStartCharacter
    : '<Any XMLNameCharacter except :>'
    ;

XMLNamespaceNameCharacter
    : XMLLetter
    | '_'
    ;

XMLQualifiedNameOrExpression
    : XMLQualifiedName
    | XMLEmbeddedExpression
    ;

XMLQualifiedName
    : XMLPrefixedName
    | XMLUnprefixedName
    ;

XMLPrefixedName
    : XMLNamespaceName ':' XMLNamespaceName
    ;

XMLUnprefixedName
    : XMLNamespaceName
    ;

네임스페이스 xmlxmlns 정의에 대한 제한 사항이 적용되며 컴파일 시간 오류가 발생합니다. XML 네임스페이스 선언에는 해당 값에 대한 포함된 식이 있을 수 없습니다. 제공된 값은 비어있지 않은 문자열 리터럴이어야 합니다. 다음은 그 예입니다.

' Declares a valid namespace
Dim customer = <db:customer xmlns:db="http://example.org/database">Bob</>

' Error: xmlns cannot be re-defined
Dim bad1 = <elem xmlns:xmlns="http://example.org/namespace"/>

' Error: cannot have an embedded expression
Dim bad2 = <elem xmlns:db=<%= "http://example.org/database" %>>Bob</>

메모. 이 사양에는 Visual Basic 언어의 동작을 설명하기에 충분한 XML 네임스페이스에 대한 설명만 포함되어 있습니다. XML 네임스페이스에 대한 자세한 내용은 .에서 http://www.w3.org/TR/REC-xml-names/찾을 수 있습니다.

XML 요소 및 특성 이름은 네임스페이스 이름을 사용하여 정규화할 수 있습니다. 파일 수준에서 선언된 네임스페이스 가져오기는 컴파일 환경에서 선언된 네임스페이스 가져오기로 묶인 선언을 묶는 컨텍스트에서 선언된 것으로 간주된다는 점을 제외하고 네임스페이스는 일반 XML에서와 같이 바인딩됩니다. 네임스페이스 이름을 찾을 수 없는 경우 컴파일 시간 오류가 발생합니다. 다음은 그 예입니다.

Imports System.Xml.Linq
Imports <xmlns:db="http://example.org/database">

Module Test
    Sub Main()
        ' Binds to the imported namespace above.
        Dim c1 = <db:customer>Bob</>

        ' Binds to the namespace declaration in the element
        Dim c2 = _
            <db:customer xmlns:db="http://example.org/database-other">Mary</>

        ' Binds to the inner namespace declaration
        Dim c3 = _
            <database xmlns:db="http://example.org/database-one">
                <db:customer xmlns:db="http://example.org/database-two">Joe</>
            </>

        ' Error: namespace db2 cannot be found
        Dim c4 = _
            <db2:customer>Jim</>
    End Sub
End Module

요소에 선언된 XML 네임스페이스는 포함된 식 내의 XML 리터럴에는 적용되지 않습니다. 다음은 그 예입니다.

' Error: Namespace prefix 'db' is not declared
Dim customer = _
    <db:customer xmlns:db="http://example.org/database">
        <%= <db:customer>Bob</> %>
    </>

메모. 포함된 식은 함수 호출을 포함하여 무엇이든 될 수 있기 때문입니다. 함수 호출에 XML 리터럴 식이 포함된 경우 프로그래머가 XML 네임스페이스를 적용할지 무시할지 여부가 명확하지 않습니다.

XML 처리 지침

XML 처리 명령으로 인해 값이 로 System.Xml.Linq.XProcessingInstruction입력됩니다. XML 처리 명령은 처리 명령 내에서 유효한 구문이므로 포함된 식을 포함할 수 없습니다.

XMLProcessingInstruction
    : '<' '?' XMLProcessingTarget ( XMLWhitespace XMLProcessingValue? )? '?' '>'
    ;

XMLProcessingTarget
    : '<Any XMLName except a casing permutation of the string "xml">'
    ;

XMLProcessingValue
    : '<Any XMLString that does not contain a question-mark followed by ">">'
    ;

XML 주석

XML 주석을 사용하면 값이 다음과 같이 System.Xml.Linq.XComment입력됩니다. XML 주석은 주석 내의 유효한 구문이므로 포함된 식을 포함할 수 없습니다.

XMLComment
    : '<' '!' '-' '-' XMLCommentCharacter* '-' '-' '>'
    ;

XMLCommentCharacter
    : '<Any XMLCharacter except dash (0x002D)>'
    | '-' '<Any XMLCharacter except dash (0x002D)>'
    ;

CDATA 섹션

CDATA 섹션을 사용하면 값이 .로 System.Xml.Linq.XCData형식화됩니다. CDATA 섹션은 CDATA 섹션 내에서 유효한 구문이므로 포함된 식을 포함할 수 없습니다.

XMLCDATASection
    : '<' '!' ( 'CDATA' '[' XMLCDATASectionString? ']' )? '>'
    ;

XMLCDATASectionString
    : '<Any XMLString that does not contain the string "]]>">'
    ;

XML 멤버 액세스 식

XML 멤버 액세스 식은 XML 값의 멤버에 액세스합니다.

XMLMemberAccessExpression
    : Expression '.' LineTerminator? '<' XMLQualifiedName '>'
    | Expression '.' LineTerminator? '@' LineTerminator? '<' XMLQualifiedName '>'
    | Expression '.' LineTerminator? '@' LineTerminator? IdentifierOrKeyword
    | Expression '.' '.' '.' LineTerminator? '<' XMLQualifiedName '>'
    ;

XML 멤버 액세스 식에는 다음 세 가지 유형이 있습니다.

  • XML 이름이 단일 점을 따르는 요소 액세스입니다. 다음은 그 예입니다.

    Dim customer = _
        <customer>
            <name>Bob</>
        </>
    Dim customerName = customer.<name>.Value
    

    요소 액세스는 함수에 매핑됩니다.

    Function Elements(name As System.Xml.Linq.XName) As _
        System.Collections.Generic.IEnumerable(Of _
            System.Xml.Linq.XNode)
    

    따라서 위의 예제는 다음과 같습니다.

    Dim customerName = customer.Elements("name").Value
    
  • 특성 액세스- Visual Basic 식별자가 점과 부호를 따르거나 XML 이름이 점과 부호 뒤에 잇는 특성 액세스입니다. 다음은 그 예입니다.

    Dim customer = <customer age="30"/>
    Dim customerAge = customer.@age
    

    특성 액세스는 함수에 매핑됩니다.

    Function AttributeValue(name As System.Xml.Linq.XName) as String
    

    따라서 위의 예제는 다음과 같습니다.

    Dim customerAge = customer.AttributeValue("age")
    

    메모. AttributeValue 확장 메서드(관련 확장 속성Value)는 현재 어셈블리에 정의되어 있지 않습니다. 확장 멤버가 필요한 경우 생성되는 어셈블리에 자동으로 정의됩니다.

  • XML 이름이 세 개의 점을 따르는 하위 항목 액세스입니다. 다음은 그 예입니다.

    Dim company = _
        <company>
            <customers>
                <customer>Bob</>
                <customer>Mary</>
                <customer>Joe</>
            </>
        </>
    Dim customers = company...<customer>
    

    하위 항목 액세스는 함수에 매핑됩니다.

    Function Descendents(name As System.Xml.Linq.XName) As _
        System.Collections.Generic.IEnumerable(Of _
            System.Xml.Linq.XElement)
    

    따라서 위의 예제는 다음과 같습니다.

    Dim customers = company.Descendants("customer")
    

XML 멤버 액세스 식의 기본 식은 값이어야 하며 형식이어야 합니다.

  • 요소 또는 하위 항목이 액세스하거나 파생된 형식 또는 System.Collections.Generic.IEnumerable(Of T) 파생 형식(위치 TSystem.Xml.Linq.XContainer 또는 파생 형식)에 액세스 System.Xml.Linq.XContainer 하는 경우

  • 특성 액세스 또는 System.Xml.Linq.XElement 파생 형식 또는 System.Collections.Generic.IEnumerable(Of T) 파생 형식인 경우, 위치 T 또는 파생 형식입니다 System.Xml.Linq.XElement .

XML 멤버 액세스 식의 이름은 비워 둘 수 없습니다. 가져오기로 정의된 네임스페이스를 사용하여 네임스페이스를 정규화할 수 있습니다. 다음은 그 예입니다.

Imports <xmlns:db="http://example.org/database">

Module Test
    Sub Main()
        Dim customer = _
            <db:customer>
                <db:name>Bob</>
            </>
        Dim name = customer.<db:name>
    End Sub
End Module

XML 멤버 액세스 식의 점 뒤 또는 꺾쇠 괄호와 이름 사이에 공백을 사용할 수 없습니다. 다음은 그 예입니다.

Dim customer = _
    <customer age="30">
        <name>Bob</>
    </>
' All the following are error cases
Dim age = customer.@ age
Dim name = customer.< name >
Dim names = customer...< name >

네임스페이스의 형식을 System.Xml.Linq 사용할 수 없는 경우 XML 멤버 액세스 식으로 인해 컴파일 시간 오류가 발생합니다.

Await 연산자

await 연산자는 Section Async 메서드에 설명된 비 동기 메서드와 관련이 있습니다.

AwaitOperatorExpression
    : 'Await' Expression
    ;

Await는 표시되는 즉시 바깥쪽 메서드 또는 람다 식에 Async 한정자가 있고 해당 Async 한정자 이후에 나타나는 경우 Await 예약된 단어입니다. 다른 곳에서는 예약되지 않습니다. 전처리기 지시문에서도 예약되지 않습니다. await 연산자는 예약어인 메서드 또는 람다 식의 본문에서만 허용됩니다. 즉시 바깥쪽 메서드 또는 람다 내에서 await 식은 a 또는 Finally Block의 Catch 본문 내부나 문 본문 SyncLock 내부 또는 쿼리 식 내에서 발생하지 않을 수 있습니다.

await 연산자는 값으로 분류되어야 하고 형식이 대기 가능한 형식이어야 Object하는 단일 식을 사용합니다. 형식이 Object 면 런타임까지 모든 처리가 지연됩니다. 다음이 모두 true이면 형식 C 이 대기 가능이라고 합니다.

  • C에는 인수가 없고 일부 형식E을 반환하는 액세스 가능한 인스턴스 또는 확장 메서드가 GetAwaiter 포함되어 있습니다.

  • E 에는 인수를 사용하지 않고 부울 형식인 읽기 가능한 인스턴스 또는 확장 속성이 포함되어 IsCompleted 있습니다.

  • E 에는 인수를 사용하지 않는 액세스 가능한 인스턴스 또는 확장 메서드가 포함되어 GetResult 있습니다.

  • E 은 (을) 구현합니다 System.Runtime.CompilerServices.INotifyCompletionICriticalNotifyCompletion.

Sub경우 GetResult await 식은 void로 분류됩니다. 그렇지 않으면 await 식이 값으로 분류되고 해당 형식이 메서드의 GetResult 반환 형식입니다.

대기할 수 있는 클래스의 예는 다음과 같습니다.

Class MyTask(Of T)
    Function GetAwaiter() As MyTaskAwaiter(Of T)
        Return New MyTaskAwaiter With {.m_Task = Me}
    End Function

    ...
End Class

Structure MyTaskAwaiter(Of T)
    Implements INotifyCompletion

    Friend m_Task As MyTask(Of T)

    ReadOnly Property IsCompleted As Boolean
        Get
            Return m_Task.IsCompleted
        End Get
    End Property

    Sub OnCompleted(r As Action) Implements INotifyCompletion.OnCompleted
        ' r is the "resumptionDelegate"
        Dim sc = SynchronizationContext.Current
        If sc Is Nothing Then
            m_Task.ContinueWith(Sub() r())
        Else
            m_Task.ContinueWith(Sub() sc.Post(Sub() r(), Nothing))
        End If
    End Sub

    Function GetResult() As T
        If m_Task.IsCanceled Then Throw New TaskCanceledException(m_Task)
        If m_Task.IsFaulted Then Throw m_Task.Exception.InnerException
        Return m_Task.Result
    End Function
End Structure

메모. 라이브러리 작성자는 자신이 호출한 것과 동일하게 SynchronizationContextOnCompleted 연속 대리자를 호출하는 패턴을 따르는 것이 좋습니다. 또한 스택 오버플로로 이어질 수 있으므로 메서드 내에서 OnCompleted 다시 시작 대리자를 동기적으로 실행해서는 안 됩니다. 대신 후속 실행을 위해 대리자를 큐에 대기해야 합니다.

제어 흐름이 연산자에 Await 도달하면 동작은 다음과 같습니다.

  1. GetAwaiter await 피연산자의 메서드가 호출됩니다. 이 호출의 결과를 awaiter라고 합니다.

  2. awaiter의 IsCompleted 속성이 검색됩니다. 결과가 true이면 다음을 수행합니다.

    1. GetResult awaiter의 메서드가 호출됩니다. 함수인 경우 GetResult await 식의 값은 이 함수의 반환 값입니다.
  3. IsCompleted 속성이 true가 아니면 다음을 수행합니다.

    1. ICriticalNotifyCompletion.UnsafeOnCompleted awaiter에서 호출되거나(awaiter의 형식 E 이 구현되는 경우) 또는 INotifyCompletion.OnCompleted (그렇지 않으면) 호출됩니다ICriticalNotifyCompletion. 두 경우 모두 비동기 메서드의 현재 인스턴스와 연결된 다시 시작 대리 자를 전달합니다.

    2. 현재 비동기 메서드 인스턴스의 제어점이 일시 중단되고 제어 흐름이 현재 호출자 (Section Async 메서드에 정의됨)에서 다시 시작됩니다.

    3. 나중에 다시 시작 대리자가 호출되는 경우

      1. 다시 시작 대리자는 먼저 호출된 시점 OnCompleted 으로 복원 System.Threading.Thread.CurrentThread.ExecutionContext 합니다.
      2. 그런 다음 비동기 메서드 인스턴스의 제어 지점에서 제어 흐름을 다시 시작합니다(섹션 비동기 메서드 참조).
      3. 여기서 위 2.1과 같이 awaiter의 메서드를 호출 GetResult 합니다.

await 피연산자 형식이 Object인 경우 이 동작은 런타임까지 지연됩니다.

  • 1단계는 인수 없이 GetAwaiter()를 호출하여 수행됩니다. 따라서 런타임에 선택적 매개 변수를 사용하여 인스턴스 메서드에 바인딩할 수 있습니다.
  • 2단계는 인수 없이 IsCompleted() 속성을 검색하고 부울로의 내장 변환을 시도하여 수행됩니다.
  • 3.a단계는 시도하고 TryCast(awaiter, ICriticalNotifyCompletion)실패 DirectCast(awaiter, INotifyCompletion)하면 수행됩니다.

3.a에 전달된 다시 시작 대리자는 한 번만 호출될 수 있습니다. 두 번 이상 호출되는 경우 동작은 정의되지 않습니다.