Delegáti (F#)
Delegát představuje volání funkce jako objekt. V jazyce F# byste obvykle měli použít hodnoty funkcí k reprezentaci funkcí jako hodnoty první třídy; Delegáti se ale používají v rozhraní .NET Framework, takže jsou potřeba, když spolupracujete s rozhraními API, která je očekávají. Mohou se také použít při vytváření knihoven navržených pro použití z jiných jazyků rozhraní .NET Framework.
Syntaxe
type delegate-typename = delegate of type1 -> type2
Poznámky
V předchozí syntaxi type1
představuje typ argumentu nebo typy a type2
představuje návratový typ. Typy argumentů, které jsou reprezentovány type1
, jsou automaticky vytvrzené. To naznačuje, že pro tento typ použijete formulář řazené kolekce členů, pokud jsou argumenty cílové funkce curried a závorky řazené řazené kolekce členů pro argumenty, které jsou již ve formuláři řazené kolekce členů. Automatické zařazení odebere sadu závorek a ponechá argument řazené kolekce členů, který odpovídá cílové metodě. Projděte si příklad kódu pro syntaxi, kterou byste měli použít v každém případě.
Delegáty je možné připojit k hodnotám funkce F# a statickým metodám nebo metodám instance. Hodnoty funkce F# je možné předat přímo jako argumenty konstruktorům delegátů. Pro statickou metodu vytvoříte delegát pomocí názvu třídy a metody. Pro metodu instance zadáte instanci objektu a metodu v jednom argumentu. V obou případech se použije operátor přístupu člena (.
).
Metoda Invoke
typu delegát volá zapouzdřenou funkci. Delegáty lze také předat jako hodnoty funkce odkazováním na název metody Invoke bez závorek.
Následující kód ukazuje syntaxi pro vytváření delegátů, které představují různé metody ve třídě. V závislosti na tom, jestli je metoda statickou metodou nebo metodou instance, a jestli má argumenty ve formuláři řazené kolekce členů nebo ve složené podobě, syntaxe pro deklarování a přiřazení delegáta je trochu jiná.
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)
Následující kód ukazuje některé z různých způsobů práce s delegáty.
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
Výstup předchozího příkladu kódu je následující.
aaaaa
bbbbb
ccccc
[|"aaa"; "bbb"|]
Názvy lze přidat k parametrům delegáta, například takto:
// 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
Názvy parametrů delegáta jsou volitelné a zobrazí se v Invoke
metodě. Nejsou nutné, aby odpovídaly názvům parametrů v implementaci. Jsou povoleny pouze pro složenou formu, ale ne pro řazenou formu.
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")
Výstup předchozího příkladu kódu je následující.
aa