Comment utilisez-vous Func et Action lors de la conception d’applications?

Tous les exemples que je peux trouver sur Func et Action sont simples comme dans celui ci-dessous où vous voyez comment ils fonctionnent techniquement, mais j’aimerais les voir utilisés dans des exemples où ils résolvent des problèmes qui ne pouvaient pas être résolus être résolu de manière plus complexe, c’est-à-dire que je sais comment ils fonctionnent et que je peux voir qu’ils sont concis et puissants , alors je veux les comprendre dans un sens plus large des problèmes qu’ils résolvent et comment les utiliser conception d’applications.

De quelle manière (patterns) utilisez-vous Func et Action pour résoudre des problèmes réels?

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TestFunc8282 { class Program { static void Main(ssortingng[] args) { //func with delegate Func convert = delegate(ssortingng s) { return s.ToUpper(); }; //func with lambda Func convert2 = s => s.Subssortingng(3, 10); //action Action recordIt = (i,title) => { Console.WriteLine("--- {0}:",title); Console.WriteLine("Adding five to {0}:", i); Console.WriteLine(i + 5); }; Console.WriteLine(convert("This is the first test.")); Console.WriteLine(convert2("This is the second test.")); recordIt(5, "First one"); recordIt(3, "Second one"); Console.ReadLine(); } } } 

Ils sont également pratiques pour le refactoring des instructions de commutateur.

Prenez l’exemple suivant (quoique simple):

 public void Move(int distance, Direction direction) { switch (direction) { case Direction.Up : Position.Y += distance; break; case Direction.Down: Position.Y -= distance; break; case Direction.Left: Position.X -= distance; break; case Direction.Right: Position.X += distance; break; } } 

Avec un délégué Action, vous pouvez le refactoriser comme suit:

 static Something() { _directionMap = new Dictionary> { { Direction.Up, (position, distance) => position.Y += distance }, { Direction.Down, (position, distance) => position.Y -= distance }, { Direction.Left, (position, distance) => position.X -= distance }, { Direction.Right, (position, distance) => position.X += distance }, }; } public void Move(int distance, Direction direction) { _directionMap[direction](this.Position, distance); } 

Utiliser linq.

 List list = { 1, 2, 3, 4 }; var even = list.Where(i => i % 2); 

Le paramètre de Where est un Func .

Les expressions lambda sont l’une de mes parties préférées de C #. 🙂

J’utilise les delegates Action et Func tout le temps. Je les déclare généralement avec la syntaxe lambda pour économiser de l’espace et les utiliser principalement pour réduire la taille des grandes méthodes. En examinant ma méthode, il arrive que des segments de code similaires se distinguent. Dans ces cas, j’emballe les segments de code similaires dans Action ou Func . Utiliser le délégué réduit le code redondant, donne une belle signature au segment de code et peut facilement être promu en tant que méthode si nécessaire.

J’avais l’habitude d’écrire du code Delphi et vous pouviez déclarer une fonction dans une fonction. Action et Func accomplissent ce même comportement pour moi en c #.

Voici un exemple de contrôles de repositionnement avec un délégué:

 private void Form1_Load(object sender, EventArgs e) { //adjust control positions without delegate int left = 24; label1.Left = left; left += label1.Width + 24; button1.Left = left; left += button1.Width + 24; checkBox1.Left = left; left += checkBox1.Width + 24; //adjust control positions with delegate. better left = 24; Action moveLeft = c => { c.Left = left; left += c.Width + 24; }; moveLeft(label1); moveLeft(button1); moveLeft(checkBox1); } 

Une chose que je l’utilise pour la mise en cache des appels de méthodes coûteux qui ne changent jamais, avec la même entrée:

 public static Func Memoize(this Func f) { Dictionary values; var methodDictionaries = new Dictionary>(); var name = f.Method.Name; if (!methodDictionaries.TryGetValue(name, out values)) { values = new Dictionary(); methodDictionaries.Add(name, values); } return a => { TResult value; if (!values.TryGetValue(a, out value)) { value = f(a); values.Add(a, value); } return value; }; } 

L’exemple par défaut de fibonacci récursif:

 class Foo { public Func Fibonacci = (n) => { return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n; }; public Foo() { Fibonacci = Fibonacci.Memoize(); for (int i=0; i<50; i++) Console.WriteLine(Fibonacci(i)); } } 

Je ne sais pas si c’est une mauvaise forme de répondre deux fois ou non à la même question, mais pour avoir des idées pour mieux utiliser ces types en général, je vous suggère de lire l’article MSDN de Jeremy Miller sur la functional programming:

Programmation fonctionnelle pour le développement de .NET au quotidien

J’utilise une action pour encapsuler correctement les opérations de firebase database en cours d’exécution dans une transaction:

 public class InTran { protected virtual ssortingng ConnSsortingng { get { return ConfigurationManager.AppSettings["YourDBConnSsortingng"]; } } public void Exec(Action a) { using (var dbTran = new DBTransaction(ConnSsortingng)) { try { a(dbTran); dbTran.Commit(); } catch { dbTran.Rollback(); throw; } } } } 

Maintenant, pour exécuter une transaction, je le fais simplement

 new InTran().Exec(tran => ...some SQL operation...); 

La classe InTran peut résider dans une bibliothèque commune, ce qui réduit la duplication et fournit un emplacement unique pour les ajustements de fonctionnalités futurs.

En les gardant génériques et en supportant de multiples arguments, cela nous permet d’éviter d’avoir à créer des delegates typescripts ou des delegates redondants puissants qui font la même chose.

En fait, j’ai trouvé cela à stackoverflow (du moins – l’idée):

 public static T Get (ssortingng cacheKey, HttpContextBase context, Func getItemCallback) where T : class { T item = Get(cacheKey, context); if (item == null) { item = getItemCallback(); context.Cache.Insert(cacheKey, item); } return item; } 

J’ai un formulaire séparé qui accepte un Func générique ou une Action dans le constructeur ainsi que du texte. Il exécute le Func / Action sur un thread séparé tout en affichant du texte dans le formulaire et en affichant une animation.

C’est dans ma bibliothèque personnelle Util, et je l’utilise chaque fois que je veux effectuer une opération de longueur moyenne et bloquer l’interface utilisateur de manière non intrusive.

J’ai envisagé de mettre également une barre de progression sur le formulaire, afin de pouvoir effectuer des opérations plus longues, mais je n’en avais pas vraiment besoin.