Teilen über


Stellvertretungen (F#)

Ein Delegat stellt einen Funktionsaufruf als Objekt dar. In F# sollten Sie in der Regel Funktionswerte verwenden, um Funktionen als Erstklassige Werte darzustellen; Stellvertretungen werden jedoch im .NET Framework verwendet, und dies ist erforderlich, wenn Sie mit APIs zusammenarbeiten, die sie erwarten. Sie können auch beim Erstellen von Bibliotheken verwendet werden, die für die Verwendung in anderen .NET Framework-Sprachen entwickelt wurden.

Syntax

type delegate-typename = delegate of type1 -> type2

Bemerkungen

In der vorherigen Syntax type1 stellt den Argumenttyp oder die Typen dar und type2 stellt den Rückgabetyp dar. Die Argumenttypen, durch die dargestellt type1 werden, werden automatisch gehärtet. Dies schlägt vor, dass Sie für diesen Typ ein Tupelformular verwenden, wenn die Argumente der Zielfunktion geschweift sind, und ein Klammer-Tupel für Argumente, die sich bereits in der Tupelform befinden. Durch die automatische Vorgehensweise wird eine Reihe von Klammern entfernt, sodass ein Tupelargument mit der Zielmethode übereinstimmt. Verweisen Sie auf das Codebeispiel für die Syntax, die Sie in jedem Fall verwenden sollten.

Stellvertretungen können F#-Funktionswerte sowie statische oder Instanzmethoden angefügt werden. F#-Funktionswerte können direkt als Argumente an Konstruktoren delegiert werden. Bei einer statischen Methode erstellen Sie den Delegaten mithilfe des Namens der Klasse und der Methode. Für eine Instanzmethode geben Sie die Objektinstanz und -methode in einem Argument an. In beiden Fällen wird der Memberzugriffsoperator (.) verwendet.

Die Invoke Methode für den Delegattyp ruft die gekapselte Funktion auf. Außerdem können Stellvertretungen als Funktionswerte übergeben werden, indem sie auf den Aufrufmethodennamen ohne die Klammern verweisen.

Der folgende Code zeigt die Syntax zum Erstellen von Delegaten, die verschiedene Methoden in einer Klasse darstellen. Je nachdem, ob es sich bei der Methode um eine statische Methode oder eine Instanzmethode handelt und ob sie Argumente in der Tupelform oder im geschweiften Formular enthält, unterscheidet sich die Syntax zum Deklarieren und Zuweisen des Delegaten etwas.

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)

Der folgende Code zeigt einige der verschiedenen Möglichkeiten, wie Sie mit Stellvertretungen arbeiten können.

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

Die Ausgabe des vorherigen Codebeispiels lautet wie folgt.

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

Namen können Stellvertretungsparametern wie folgt hinzugefügt werden:

// 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

Delegatparameternamen sind optional und werden in der Invoke Methode angezeigt. Sie müssen nicht mit den Parameternamen in der Implementierung übereinstimmen. Sie sind nur für die geschweifte Form, aber nicht für die tuplierte Form zulässig.

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")

Die Ausgabe des vorherigen Codebeispiels lautet wie folgt.

aa

Siehe auch