Qu’est-ce que Func
et à quoi sert-il?
Func
est un type de délégué prédéfini pour une méthode qui renvoie une valeur de type T
En d’autres termes, vous pouvez utiliser ce type pour référencer une méthode qui renvoie une valeur de T
Par exemple
public static ssortingng GetMessage() { return "Hello world"; }
peut être référencé comme ça
Func f = GetMessage;
Pensez-y comme un espace réservé. Cela peut être très utile lorsque vous avez du code qui suit un certain modèle, mais ne doit pas être lié à une fonctionnalité particulière.
Par exemple, considérez la méthode d’extension Enumerable.Select
.
Cette méthode prend un Func
au lieu de toute fonction concrète. Cela lui permet d’être utilisé dans n’importe quel contexte où le modèle ci-dessus s’applique.
Par exemple, disons que j’ai une List
et que je veux juste le nom de chaque personne dans la liste. Je peux le faire:
var names = people.Select(p => p.Name);
Ou dire que je veux l’ âge de chaque personne:
var ages = people.Select(p => p.Age);
Tout de suite, vous pouvez voir comment j’ai pu exploiter le même code représentant un motif (avec Select
) avec deux fonctions différentes ( p => p.Name
et p => p.Age
).
L’alternative serait d’écrire une version différente de Select
chaque fois que vous vouliez numériser une séquence pour un type de valeur différent. Donc, pour obtenir le même effet que ci-dessus, il me faudrait:
// Presumably, the code inside these two methods would look almost identical; // the only difference would be the part that actually selects a value // based on a Person. var names = GetPersonNames(people); var ages = GetPersonAges(people);
Avec un délégué agissant comme espace réservé, je me libère de devoir écrire le même schéma encore et encore dans des cas comme celui-ci.
Func
représente une fonction qui prend les arguments (T1, T2, …, Tn) et renvoie Tr.
Par exemple, si vous avez une fonction:
double sqr(double x) { return x * x; }
Vous pourriez le sauvegarder en tant que variable de fonction:
Func f1 = sqr; Func f2 = x => x * x;
Et puis utilisez exactement comme vous utiliseriez sqr:
f1(2); Console.WriteLine(f2(f1(4)));
etc.
Rappelez-vous cependant que c’est un délégué, pour plus d’informations, consultez la documentation.
Func
et les autres delegates Func
génériques prédéfinis ( Func
, Func
et autres) sont des delegates génériques qui renvoient le type du dernier paramètre générique.
Si vous avez une fonction qui doit renvoyer différents types, selon les parameters, vous pouvez utiliser un délégué Func
, en spécifiant le type de retour.
C’est juste un délégué générique prédéfini. En l’utilisant, vous n’avez pas besoin de déclarer chaque délégué. Il y a un autre délégué prédéfini, Action
, qui est le même mais renvoie un vide.
Je trouve Func
très utile lorsque je crée un composant à personnaliser “à la volée”.
Prenez cet exemple très simple: un PrintListToConsole
.
Un object très simple qui imprime cette liste d’objects sur la console. Vous voulez laisser le développeur qui l’utilise personnaliser la sortie.
Par exemple, vous voulez le laisser définir un type particulier de format numérique, etc.
Sans func
Tout d’abord, vous devez créer une interface pour une classe qui prend l’entrée et génère la chaîne à imprimer sur la console.
interface PrintListConsoleRender { Ssortingng Render(T input); }
Ensuite, vous devez créer la classe PrintListToConsole
qui prend l’interface créée précédemment et l’utilise sur chaque élément de la liste.
class PrintListToConsole { private PrintListConsoleRender _renderer; public void SetRenderer(PrintListConsoleRender r) { // this is the point where I can personalize the render mechanism _renderer = r; } public void PrintToConsole(List list) { foreach (var item in list) { Console.Write(_renderer.Render(item)); } } }
Le développeur qui doit utiliser votre composant doit:
implémenter l’interface
passer la vraie classe à la PrintListToConsole
class MyRenderer : PrintListConsoleRender { public Ssortingng Render(int input) { return "Number: " + input; } } class Program { static void Main(ssortingng[] args) { var list = new List { 1, 2, 3 }; var printer = new PrintListToConsole (); printer.SetRenderer(new MyRenderer()); printer.PrintToConsole(list); ssortingng result = Console.ReadLine(); } }
Utiliser Func c’est beaucoup plus simple
A l’intérieur du composant, vous définissez un paramètre de type Func
qui représente une interface d’une fonction qui prend un paramètre d’entrée de type T et retourne une chaîne (la sortie pour la console)
class PrintListToConsole { private Func _renderFunc; public void SetRenderFunc(Func r) { // this is the point where I can set the render mechanism _renderFunc = r; } public void Print(List list) { foreach (var item in list) { Console.Write(_renderFunc(item)); } } }
Lorsque le développeur utilise votre composant, il transmet simplement au composant l’implémentation du type Func
, c’est-à-dire une fonction qui crée la sortie pour la console.
class Program { static void Main(ssortingng[] args) { var list = new Array[1, 2, 3]; var printer = new PrintListToConsole(); printer.SetRenderFunc((o) => "Number:" + o); printer.Print(); ssortingng result = Console.ReadLine(); } }
Func
vous permet de définir une interface de méthode générique à la volée. Vous définissez le type de l’entrée et le type de sortie. Simple et concis