How do you use Func<> and Action<> when designing applications?
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:
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, 2022Comments
-
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 over 14 yearsThe parameter for the
Where
method is actually aFunc<T, bool>
, not anAction<T, bool>
. -
Yannick Motton over 14 yearsThe msdn seems to suggest it is a Func<TSource, bool> msdn.microsoft.com/en-us/library/bb534803.aspx
-
Daniel A. White over 14 years@Yannick M. True. But in my example its derived from the
T
in the genericList
. -
Yannick Motton over 14 yearsI know, my comment was to you thinking it was an
Action<>
. AnAction
has returntype void, so it is illogical to assume it would be used in where. -
Daniel A. White over 14 yearsOh I though you were referring to it with
TSource
-
Arnis Lapsa over 14 yearsNo. Unfortunately i cannot. It was one of those "tips and tricks" questions.
-
Daniel A. White over 14 years@leppie - True, but many compilers today have that internally.
-
Robert Rossney over 14 yearsThis 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
orstring
. -
Alex over 14 yearsThese are generics, not Func or Action. Different animal.
-
Joel Coehoorn over 14 yearsI 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 over 14 yearsInterestingly, same number of lines
-
Yannick Motton over 14 yearsIt 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 over 14 yearsSometimes i'm wondering. Do people read before they post? @Alex, check out function parameters once more.
-
Samantha Branham over 14 yearsThis 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 over 10 yearssorry can you eloborate more. ? What is significance of using like this ?
-
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 over 7 yearsThis might help akshaya-m.blogspot.com/2015/03/…