Délégués (F#)
Un délégué représente un appel de fonction en tant qu'objet. En F#, vous devez généralement utiliser des valeurs de fonction pour représenter des fonctions comme valeurs de première classe ; toutefois, les délégués étant utilisés dans le .NET Framework, ils sont nécessaires lorsque vous interagissez avec des API qui les attendent. Ils peuvent également être utilisés lors de la création de bibliothèques conçues pour une utilisation à partir d'autres langages .NET Framework.
type delegate-typename = delegate of type1 -> type2
Notes
Dans la syntaxe précédente, type1 représente le ou les types d'argument, et type2 représente le type de retour. Les types d'argument représentés par type1 sont automatiquement curryfiés. Cela laisse entendre que, pour ce type, vous utilisez une forme de tuple si les arguments de la fonction cible sont curryfiés, et un tuple entre parenthèses pour les arguments qui sont déjà sous forme de tuple. La curryfication automatique supprime un jeu de parenthèses, laissant ainsi un argument de tuple qui correspond à la méthode cible. Reportez-vous à l'exemple de code pour la syntaxe à utiliser dans chaque cas.
Les délégués peuvent être joints à des valeurs de fonction F# ainsi qu'à des méthodes statiques ou d'instance. Les valeurs de fonction F# peuvent être passées directement en tant qu'arguments aux constructeurs délégués. Pour une méthode statique, construisez le délégué à l'aide du nom de la classe et de la méthode. Pour une méthode d'instance, indiquez l'instance et la méthode d'objet dans un argument. Dans les deux cas, l'opérateur d'accès de membre (.) est utilisé.
La méthode Invoke sur le type délégué appelle la fonction encapsulée. De même, les délégués peuvent être passés en tant que valeurs de fonction en référençant le nom de la méthode Invoke sans les parenthèses.
Le code suivant indique la syntaxe utilisée pour créer des délégués représentant différentes méthodes dans une classe. Selon que la méthode est une méthode statique ou une méthode d'instance, et selon qu'elle possède des arguments sous forme de tuple ou sous forme curryfiée, la syntaxe pour la déclaration et l'assignation du délégué diffère quelque peu.
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 = new Delegate1( Test1.add )
let del2 : Delegate2 = new 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 = new Delegate1( testObject.Add )
let del4 : Delegate2 = new 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)
Le code suivant affiche certaines des différentes manières que vous pouvez utiliser avec les délégués.
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 = new 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
La sortie du code précédent est la suivante.
aaaaa
bbbbb
ccccc
[|"aaa"; "bbb"|]