Ombud (F#)
Ett ombud representerar ett funktionsanrop som ett objekt. I F#bör du vanligtvis använda funktionsvärden för att representera funktioner som förstklassiga värden. Ombud används dock i .NET Framework och behövs därför när du samverkar med API:er som förväntar sig dem. De kan också användas när du redigerar bibliotek som är utformade för användning från andra .NET Framework-språk.
Syntax
type delegate-typename = delegate of type1 -> type2
Kommentarer
I den föregående syntaxen type1
representerar argumenttypen eller typerna och type2
representerar returtypen. Argumenttyperna som representerasavs type1
automatiskt. Detta tyder på att för den här typen använder du ett tupplare om argumenten för målfunktionen är currybaserade och en parentesiserad tupplar för argument som redan finns i tuppelns form. Den automatiska curryingen tar bort en uppsättning parenteser, vilket lämnar ett tupppelargument som matchar målmetoden. Se kodexemplet för den syntax som du bör använda i varje enskilt fall.
Ombud kan kopplas till F#-funktionsvärden och statiska metoder eller instansmetoder. F#-funktionsvärden kan skickas direkt som argument för att delegera konstruktorer. För en statisk metod skapar du ombudet med hjälp av namnet på klassen och metoden. För en instansmetod anger du objektinstansen och -metoden i ett argument. I båda fallen används medlemsåtkomstoperatorn (.
).
Metoden Invoke
för ombudstypen anropar den inkapslade funktionen. Ombud kan också skickas som funktionsvärden genom att referera till metoden Invoke name without the parentheses (Anropa metodnamn utan parenteser).
Följande kod visar syntaxen för att skapa ombud som representerar olika metoder i en klass. Beroende på om metoden är en statisk metod eller en instansmetod och om den har argument i tuppelns form eller formuläret curry är syntaxen för att deklarera och tilldela ombudet lite annorlunda.
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)
Följande kod visar några av de olika sätt som du kan arbeta med ombud på.
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
Utdata från föregående kodexempel är följande.
aaaaa
bbbbb
ccccc
[|"aaa"; "bbb"|]
Namn kan läggas till i delegera parametrar så här:
// 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
Ombudsparameternamn är valfria och visas i Invoke
-metoden. De krävs inte för att matcha parameternamnen i implementeringen. De är bara tillåtna för curryformen men inte den tupled formen.
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")
Utdata från föregående kodexempel är följande.
aa