대리자(F#)

대리자는 함수 호출을 개체로 나타냅니다. F#에서는 일반적으로 함수 값을 사용하여 함수를 일류 값으로 나타내야 합니다. 그러나 대리자는 .NET Framework에서 사용되므로 필요한 API와 상호 운용할 때 필요합니다. 다른 .NET Framework 언어에서 사용하도록 설계된 라이브러리를 작성할 때도 사용할 수 있습니다.

구문

type delegate-typename = delegate of type1 -> type2

설명

이전 구문 type1 에서 인수 형식 또는 형식을 나타내고 type2 반환 형식을 나타냅니다. 표시되는 type1 인수 형식은 자동으로 커서가 지정됩니다. 이는 대상 함수의 인수가 튜플 형식인 경우 튜플 폼을 사용하고 튜플 형식에 이미 있는 인수에 대해 괄호가 지정된 튜플을 사용한다는 것을 시사합니다. 자동 커리는 괄호 집합을 제거하여 대상 메서드와 일치하는 튜플 인수를 남깁니다. 각 사례에서 사용해야 하는 구문에 대한 코드 예제를 참조하세요.

대리자는 F# 함수 값 및 정적 또는 인스턴스 메서드에 연결할 수 있습니다. F# 함수 값을 대리자 생성자에 대한 인수로 직접 전달할 수 있습니다. 정적 메서드의 경우 클래스 이름과 메서드를 사용하여 대리자를 생성합니다. 인스턴스 메서드의 경우 개체 인스턴스와 메서드를 하나의 인수로 제공합니다. 두 경우 모두 멤버 액세스 연산자(.)가 사용됩니다.

대리자 형식의 메서드는 Invoke 캡슐화된 함수를 호출합니다. 또한 대리자는 괄호 없이 Invoke 메서드 이름을 참조하여 함수 값으로 전달될 수 있습니다.

다음 코드는 클래스의 다양한 메서드를 나타내는 대리자를 만들기 위한 구문을 보여 줍니다. 메서드가 정적 메서드인지 인스턴스 메서드인지, 튜플 형식에 인수가 있는지 또는 커리 형식인지에 따라 대리자를 선언하고 할당하는 구문은 약간 다릅니다.

type Test1() =
  static member add(a : int, b : int) =
     a + b
  static member add2 (a : int) (b : int) =
     a + b

  member x.Add(a : int, b : int) =
     a + b
  member x.Add2 (a : int) (b : int) =
     a + b


// Delegate1 works with tuple arguments.
type Delegate1 = delegate of (int * int) -> int
// Delegate2 works with curried arguments.
type Delegate2 = delegate of int * int -> int

let InvokeDelegate1 (dlg: Delegate1) (a: int) (b: int) =
   dlg.Invoke(a, b)
let InvokeDelegate2 (dlg: Delegate2) (a: int) (b: int) =
   dlg.Invoke(a, b)

// For static methods, use the class name, the dot operator, and the
// name of the static method.
let del1 = Delegate1(Test1.add)
let del2 = Delegate2(Test1.add2)

let testObject = Test1()

// For instance methods, use the instance value name, the dot operator, and the instance method name.
let del3 = Delegate1(testObject.Add)
let del4 = Delegate2(testObject.Add2)

for (a, b) in [ (100, 200); (10, 20) ] do
  printfn "%d + %d = %d" a b (InvokeDelegate1 del1 a b)
  printfn "%d + %d = %d" a b (InvokeDelegate2 del2 a b)
  printfn "%d + %d = %d" a b (InvokeDelegate1 del3 a b)
  printfn "%d + %d = %d" a b (InvokeDelegate2 del4 a b)

다음 코드에서는 대리자를 사용하여 작업할 수 있는 몇 가지 방법을 보여 줍니다.

type Delegate1 = delegate of int * char -> string

let replicate n c = String.replicate n (string c)

// An F# function value constructed from an unapplied let-bound function
let function1 = replicate

// A delegate object constructed from an F# function value
let delObject = Delegate1(function1)

// An F# function value constructed from an unapplied .NET member
let functionValue = delObject.Invoke

List.map (fun c -> functionValue(5,c)) ['a'; 'b'; 'c']
|> List.iter (printfn "%s")

// Or if you want to get back the same curried signature
let replicate' n c =  delObject.Invoke(n,c)

// You can pass a lambda expression as an argument to a function expecting a compatible delegate type
// System.Array.ConvertAll takes an array and a converter delegate that transforms an element from
// one type to another according to a specified function.
let stringArray = System.Array.ConvertAll([|'a';'b'|], fun c -> replicate' 3 c)
printfn "%A" stringArray

이전 코드 예제의 출력은 다음과 같습니다.

aaaaa
bbbbb
ccccc
[|"aaa"; "bbb"|]

다음과 같이 대리자 매개 변수에 이름을 추가할 수 있습니다.

// http://www.pinvoke.net/default.aspx/user32/WinEventDelegate.html
type WinEventDelegate = delegate of hWinEventHook:nativeint * eventType:uint32 * hWnd:nativeint * idObject:int * idChild:int * dwEventThread:uint32 * dwmsEventTime:uint32 -> unit

대리자 매개 변수 이름은 선택 사항이며 메서드에 Invoke 표시됩니다. 구현의 매개 변수 이름과 일치시킬 필요는 없습니다. 이 형식은 튜플된 양식이 아니라 커리 양식에만 사용할 수 있습니다.

type D1 = delegate of item1: int * item2: string -> unit
let a = D1(fun a b -> printf "%s" b)
a.Invoke(item2 = "a", item1 = 1) // Calling with named arguments

type D2 = delegate of int * item2: string -> unit // Omitting one name
let b = D2(fun a b -> printf "%s" b)
b.Invoke(1, item2 = "a")

이전 코드 예제의 출력은 다음과 같습니다.

aa

참고 항목