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

31,767

Solution 1

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

Solution 2

Using linq.

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

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

The parameter for Where is an Func<int, bool>.

Lambda expressions are one of my favorite parts of C#. :)

Solution 3

I use the Action and Func delegates all the time. I typically declare them with lambda syntax to save space and use them primarily to reduce the size of large methods. As I review my method, sometimes code segments that are similar will stand out. In those cases, I wrap up the similar code segments into Action or Func. Using the delegate reduces redundant code, give a nice signature to the code segment and can easily be promoted to a method if need be.

I used to write Delphi code and you could declare a function within a function. Action and Func accomplish this same behavior for me in c#.

Here's a sample of repositioning controls with a delegate:

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

Solution 4

One thing I use it for is Caching of expensive method calls that never change given the same input:

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

The default recursive fibonacci example:

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

Solution 5

Dunno if it's bad form to answer the same question twice or not, but to get some ideas for better uses of these types in general I suggest reading Jeremy Miller's MSDN article on Functional Programming:

Functional Programming for Everyday .NET Development

Share:
31,767
Angry Dan
Author by

Angry Dan

web/software developer, .NET, C#, WPF, PHP, software trainer, English teacher, have philosophy degree, love languages, run marathons my tweets: http://www.twitter.com/edward_tanguay my runs: http://www.tanguay.info/run my code: http://www.tanguay.info/web my publications: PHP 5.3 training video (8 hours, video2brain) my projects: http://www.tanguay.info

Updated on July 05, 2022

Comments

  • Angry Dan
    Angry Dan almost 2 years

    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();
    
            }
        }
    }
    
  • LukeH
    LukeH over 14 years
    The parameter for the Where method is actually a Func<T, bool>, not an Action<T, bool>.
  • Yannick Motton
    Yannick Motton over 14 years
    The msdn seems to suggest it is a Func<TSource, bool> msdn.microsoft.com/en-us/library/bb534803.aspx
  • Daniel A. White
    Daniel A. White over 14 years
    @Yannick M. True. But in my example its derived from the T in the generic List.
  • Yannick Motton
    Yannick Motton over 14 years
    I know, my comment was to you thinking it was an Action<>. An Action has returntype void, so it is illogical to assume it would be used in where.
  • Daniel A. White
    Daniel A. White over 14 years
    Oh I though you were referring to it with TSource
  • Arnis Lapsa
    Arnis Lapsa over 14 years
    No. Unfortunately i cannot. It was one of those "tips and tricks" questions.
  • Daniel A. White
    Daniel A. White over 14 years
    @leppie - True, but many compilers today have that internally.
  • Robert Rossney
    Robert Rossney over 14 years
    This is an incredibly useful technique for many reasons. Unlike switch statements, for instance, you can populate action maps dynamically from external data. Also, the key doesn't have to be an int or string.
  • Alex
    Alex over 14 years
    These are generics, not Func or Action. Different animal.
  • Joel Coehoorn
    Joel Coehoorn over 14 years
    I think there's a bug here: shouldn't fib call itself, or do you mean it to call the property (which is a delegate reference to itself?)
  • JustLoren
    JustLoren over 14 years
    Interestingly, same number of lines
  • Yannick Motton
    Yannick Motton over 14 years
    It should indeed call the delegate. Otherwise you wouldn't be able to intercept the recursive calls. The idea is to encapsulate the call, so the cache actually becomes useful.
  • Arnis Lapsa
    Arnis Lapsa over 14 years
    Sometimes i'm wondering. Do people read before they post? @Alex, check out function parameters once more.
  • Samantha Branham
    Samantha Branham over 14 years
    This is powerful when needed, but remember that switch statements are often very fast, at least in implementations where jump tables can be used. I can't say whether or not .NET uses them or not.
  • shanmugharaj
    shanmugharaj over 10 years
    sorry can you eloborate more. ? What is significance of using like this ?
  • nawfal
    nawfal over 10 years
    @JustLoren the bigger the action becomes the lines come down. But that is beside the point anyway, you have less maintenance nightmare, which is the real deal.
  • Akxaya
    Akxaya over 7 years