Search code examples
c#delegatesactionanonymous-methodsfunc

How do you use Func<> and Action<> when designing applications?


All the examples I can find about Func<> and Action<> are simple as in the one below where you see how they technically work but I would like to see them used in examples where they solve problems that previously could not be solved or could be solved only in a more complex way, i.e. I know how they work and I can see they are terse and powerful, so I want to understand them in a larger sense of what kinds of problems they solve and how I could use them in the design of applications.

In what ways (patterns) do you use Func<> and Action<> to solve real problems?

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();

        }
    }
}

Solution

  • They're also handy for refactoring switch statements.

    Take the following (albeit simple) example:

    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;
        }
    }
    

    With an Action delegate, you can refactor it as follows:

    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);
    }