형식 확장

형식 확장(확대라고도 함)은 이전에 정의된 개체 형식에 새 멤버를 추가할 수 있는 기능 제품군입니다. 세 가지 기능은 다음과 같습니다.

  • 내장 형식 확장
  • 선택적 형식 확장
  • 확장 메서드

각 시나리오는 서로 다른 시나리오에서 사용할 수 있으며 서로 다른 장단 사항이 있습니다.

구문

// Intrinsic and optional extensions
type typename with
    member self-identifier.member-name =
        body
    ...

// Extension methods
open System.Runtime.CompilerServices

[<Extension>]
type Extensions() =
    [<Extension>]
    static member extension-name (ty: typename, [args]) =
        body
    ...

내장 형식 확장

내장 형식 확장은 사용자 정의 형식을 확장하는 형식 확장입니다.

내장 형식 확장명은 확장 중인 형식과 동일한 파일 동일한 네임스페이스 또는 모듈에 정의되어야 합니다. 다른 정의는 선택적 형식 확장이 됩니다.

내장 형식 확장은 경우에 따라 기능을 형식 선언과 구분하는 클린 방법입니다. 다음 예제에서는 내장 형식 확장을 정의하는 방법을 보여 줍니다.

namespace Example

type Variant =
    | Num of int
    | Str of string
  
module Variant =
    let print v =
        match v with
        | Num n -> printf "Num %d" n
        | Str s -> printf "Str %s" s

// Add a member to Variant as an extension
type Variant with
    member x.Print() = Variant.print x

형식 확장을 사용하면 다음을 각각 구분할 수 있습니다.

  • 형식의 선언입니다.Variant
  • "shape"에 따라 클래스를 인쇄 Variant 하는 기능
  • 개체 스타일 .표기법을 사용하여 인쇄 기능에 액세스하는 방법

이는 모든 항목을 에 Variant멤버로 정의하는 대안입니다. 본질적으로 더 나은 방법은 아니지만 일부 상황에서는 클린 기능의 표현일 수 있습니다.

내장 형식 확장은 보강된 형식의 멤버로 컴파일되며, 리플렉션으로 형식을 검사할 때 형식에 표시됩니다.

선택적 형식 확장

선택적 형식 확장은 확장 중인 형식의 원래 모듈, 네임스페이스 또는 어셈블리 외부에 나타나는 확장입니다.

선택적 형식 확장은 직접 정의하지 않은 형식을 확장하는 데 유용합니다. 예시:

module Extensions

type IEnumerable<'T> with
    /// Repeat each element of the sequence n times
    member xs.RepeatElements(n: int) =
        seq {
            for x in xs do
                for _ in 1 .. n -> x
        }

이제 작업 중인 범위에서 모듈이 열리는 한 구성원인 Extensions 것처럼 IEnumerable<T> 액세스할 RepeatElements 수 있습니다.

선택적 확장은 리플렉션으로 검사할 때 확장 형식에 표시되지 않습니다. 선택적 확장은 모듈에 있어야 하며 확장이 포함된 모듈이 열려 있거나 범위에 있는 경우에만 범위에 있습니다.

선택적 확장 멤버는 개체 인스턴스가 첫 번째 매개 변수로 암시적으로 전달되는 정적 멤버로 컴파일됩니다. 그러나 선언 방법에 따라 인스턴스 멤버 또는 정적 멤버인 것처럼 작동합니다.

선택적 확장 멤버는 C# 또는 Visual Basic 소비자에게도 표시되지 않습니다. 다른 F# 코드에서만 사용할 수 있습니다.

내장 및 선택적 형식 확장의 제네릭 제한 사항

형식 변수가 제한된 제네릭 형식에서 형식 확장을 선언할 수 있습니다. 확장 선언의 제약 조건이 선언된 형식의 제약 조건과 일치해야 합니다.

그러나 선언된 형식과 형식 확장 간에 제약 조건이 일치하더라도 선언된 형식과 형식 매개 변수에 다른 요구 사항을 적용하는 확장 멤버의 본문에서 제약 조건을 유추할 수 있습니다. 예시:

open System.Collections.Generic

// NOT POSSIBLE AND FAILS TO COMPILE!
//
// The member 'Sum' has a different requirement on 'T than the type IEnumerable<'T>
type IEnumerable<'T> with
    member this.Sum() = Seq.sum this

선택적 형식 확장에서 이 코드를 사용할 수 있는 방법은 없습니다.

  • 마찬가지로 멤버는 Sum 형식 확장에서 정의하는 것과 다른 제약 조건 'T (static member get_Zerostatic member (+))을 가집니다.
  • 형식 확장에서 정의된 제약 조건과 더 이상 일치하지 않는 것과 Sum 동일한 제약 조건을 IEnumerable<'T>갖도록 수정합니다.
  • 변경 member this.Sum 하면 member inline this.Sum 형식 제약 조건이 일치하지 않는 오류가 발생합니다.

원하는 것은 "공간에 부동"하고 형식을 확장하는 것처럼 표시할 수 있는 정적 메서드입니다. 확장 메서드가 필요한 위치입니다.

확장 메서드

마지막으로 확장 메서드("C# 스타일 확장 멤버"라고도 함)는 F#에서 클래스의 정적 멤버 메서드로 선언할 수 있습니다.

확장 메서드는 형식 변수를 제한하는 제네릭 형식의 확장을 정의하려는 경우에 유용합니다. 예시:

namespace Extensions

open System.Collections.Generic
open System.Runtime.CompilerServices

[<Extension>]
type IEnumerableExtensions =
    [<Extension>]
    static member inline Sum(xs: IEnumerable<'T>) = Seq.sum xs

이 코드를 사용하면 열려 있거나 범위에 있는 한 이 코드가 정의된 IEnumerable<T>Extensions 것처럼 Sum 표시됩니다.

VB.NET 코드에 확장을 사용할 수 있게 하려면 어셈블리 수준에서 추가 ExtensionAttribute 가 필요합니다.

module AssemblyInfo
open System.Runtime.CompilerServices
[<assembly:Extension>]
do ()

기타 설명

형식 확장에는 다음과 같은 특성도 있습니다.

  • 액세스할 수 있는 모든 형식을 확장할 수 있습니다.
  • 내장 형식 및 선택적 형식 확장은 메서드뿐만 아니라 모든 멤버 형식을 정의 수 있습니다. 예를 들어 확장 속성도 가능합니다.
  • 구문토큰은 self-identifier 일반 멤버와 마찬가지로 호출되는 형식의 인스턴스를 나타냅니다.
  • 확장 멤버는 정적 또는 인스턴스 멤버일 수 있습니다.
  • 형식 확장의 형식 변수는 선언된 형식의 제약 조건과 일치해야 합니다.

형식 확장에도 다음과 같은 제한 사항이 있습니다.

  • 형식 확장은 가상 또는 추상 메서드를 지원하지 않습니다.
  • 형식 확장은 메서드를 확대로 재정의할 수 없습니다.
  • 형식 확장은 정적으로 확인된 형식 매개 변수를 지원하지 않습니다.
  • 선택적 형식 확장은 생성자를 확대로 지원하지 않습니다.
  • 형식 확장은 형식 약어정의할 수 없습니다.
  • 형식 확장은 유효 byref<'T> 하지 않습니다(선언할 수 있지만).
  • 형식 확장은 특성에 유효하지 않습니다(선언할 수 있지만).
  • 동일한 이름의 다른 메서드를 오버로드하는 확장을 정의할 수 있지만, 모호한 호출이 있는 경우 F# 컴파일러에서 비 확장 메서드에 대한 기본 설정을 제공합니다.

마지막으로 한 형식에 대해 여러 내장 형식 확장이 있는 경우 모든 멤버는 고유해야 합니다. 선택적 형식 확장의 경우 동일한 형식의 다른 형식 확장에 있는 멤버의 이름은 같을 수 있습니다. 모호성 오류는 클라이언트 코드가 동일한 멤버 이름을 정의하는 두 개의 서로 다른 범위를 여는 경우에만 발생합니다.

참고 항목