69 votes

Comment utiliser Func<> et Action<> lors de la conception d'applications ?

Tous les exemples que je peux trouver sur Func<> et Action<> sont simple comme dans l'exemple ci-dessous où l'on voit comment ils fonctionnent techniquement, mais j'aimerais qu'ils soient utilisés dans des exemples où ils résolvent des problèmes qui ne pouvaient pas être résolus auparavant ou qui ne pouvaient l'être que d'une manière plus complexe, c'est-à-dire que je sais comment ils fonctionnent et je peux voir qu'ils sont efficaces. laconique et puissant Je veux donc les comprendre d'un point de vue sens plus large des types de problèmes qu'ils résolvent et de la manière dont je pourrais les utiliser dans la conception d'applications.

De quelles manières (modèles) 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(string[] args)
        {
            //func with delegate
            Func<string, string> convert = delegate(string s)
            {
                return s.ToUpper();
            };

            //func with lambda
            Func<string, string> convert2 = s => s.Substring(3, 10);

            //action
            Action<int,string> 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();

        }
    }
}

56voto

Craig Vermeer Points 1262

Ils sont également utiles pour remanier les instructions de commutation.

Prenons l'exemple suivant (bien que 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é d'action, vous pouvez le remanier comme suit :

static Something()
{
    _directionMap = new Dictionary<Direction, Action<Position, int>>
    {
        { 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);
}

15voto

Daniel A. White Points 91889

Utilisation de linq.

List<int> list = { 1, 2, 3, 4 };

var even = list.Where(i => i % 2);

Le paramètre pour Where est un Func<int, bool> .

Les expressions lambda sont l'une de mes parties préférées de C# :)

14voto

Steve Points 1130

J'utilise le Action y Func les délégués tout le temps. Je les déclare généralement avec la syntaxe lambda pour économiser de l'espace et je les utilise principalement pour réduire la taille des grandes méthodes. Lorsque je révise ma méthode, il arrive que des segments de code similaires ressortent. Dans ce cas, je regroupe les segments de code similaires en Action o Func . L'utilisation du délégué réduit le code redondant, donne une belle signature au segment de code et peut facilement être promu en méthode si nécessaire.

J'avais l'habitude d'écrire du code Delphi et vous pouviez déclarer une fonction à l'intérieur d'une fonction. Action et Func permettent d'obtenir le même résultat en c#.

Voici un exemple de repositionnement de contrôles à l'aide d'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<Control> moveLeft = c => 
    {
        c.Left = left;
        left += c.Width + 24; 
    };
    moveLeft(label1);
    moveLeft(button1);
    moveLeft(checkBox1);
}

9voto

Yannick Motton Points 9806

Je l'utilise notamment pour la mise en cache des appels de méthodes coûteuses qui ne changent jamais avec les mêmes données d'entrée :

public static Func<TArgument, TResult> Memoize<TArgument, TResult>(this Func<TArgument, TResult> f)
{
    Dictionary<TArgument, TResult> values;

    var methodDictionaries = new Dictionary<string, Dictionary<TArgument, TResult>>();

    var name = f.Method.Name;
    if (!methodDictionaries.TryGetValue(name, out values))
    {
        values = new Dictionary<TArgument, TResult>();

        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 récursif de fibonacci par défaut :

class Foo
{
  public Func<int,int> 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));
  }
}

6voto

Craig Vermeer Points 1262

Je ne sais pas si c'est mal vu de répondre deux fois à la même question, mais pour trouver des idées pour une meilleure utilisation de ces types en général, je suggère de lire l'article MSDN de Jeremy Miller sur la programmation fonctionnelle :

Programmation fonctionnelle pour le développement .NET au quotidien

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X