73

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

        }
    }
}
Edward Tanguay
  • 189,012
  • 314
  • 712
  • 1,047

9 Answers9

59

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);
}
Aydin
  • 15,016
  • 4
  • 32
  • 42
Craig Vermeer
  • 1,987
  • 19
  • 29
  • 12
    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`. – Robert Rossney Oct 08 '09 at 16:20
  • 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. – Samantha Branham Oct 21 '09 at 01:34
  • This might help http://akshaya-m.blogspot.com/2015/03/elegant-way-to-switch-if-else.html#comment-form – Akxaya Nov 24 '16 at 00:40
15

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#. :)

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
14

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);
}
nawfal
  • 70,104
  • 56
  • 326
  • 368
Steve
  • 2,153
  • 4
  • 22
  • 31
  • 5
    Interestingly, same number of lines – JustLoren Oct 08 '09 at 21:02
  • @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. – nawfal Dec 13 '13 at 11:53
9

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));
  }
}
Yannick Motton
  • 34,761
  • 4
  • 39
  • 55
  • 1
    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?) – Joel Coehoorn Oct 08 '09 at 20:56
  • 1
    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. – Yannick Motton Oct 08 '09 at 21:06
6

I use an Action to nicely encapsulate executing database operations in a transaction:

public class InTran
{
    protected virtual string ConnString
    {
        get { return ConfigurationManager.AppSettings["YourDBConnString"]; }
    }

    public void Exec(Action<DBTransaction> a)
    {
        using (var dbTran = new DBTransaction(ConnString))
        {
            try
            {
                a(dbTran);
                dbTran.Commit();
            }
            catch
            {
                dbTran.Rollback();
                throw;
            }
        }
    }
}

Now to execute in a transaction I simply do

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

The InTran class can reside in a common library, reducing duplication and provides a singe location for future functionality adjustments.

Todd Stout
  • 3,687
  • 3
  • 24
  • 29
6

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

Craig Vermeer
  • 1,987
  • 19
  • 29
2

Actually, i found this at stackoverflow (at least - the idea):

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

    return item;
}
nawfal
  • 70,104
  • 56
  • 326
  • 368
Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
2

By keeping them generic and supporting multiple arguments, it allows us to avoid having to create strong typed delegates or redundant delegates that do the same thing.

Greg
  • 23,155
  • 11
  • 57
  • 79
Hasani Blackwell
  • 2,026
  • 1
  • 13
  • 10
0

I have a separate form that accepts a generic Func or an Action in the constructor as well as some text. It executes the Func/Action on a separate thread while displaying some text in the form and showing an animation.

It's in my personal Util library, and I use it whenever I want to do a medium length operation and block the UI in a non-intrusive way.

I considered putting a progress bar on the form as well, so that it could perform longer running operations but I haven't really needed it to yet.

Steven Evers
  • 16,649
  • 19
  • 79
  • 126