Thursday, August 7, 2008

Action<> and Func<> delegates

these new generic delegates were added in .NET 3.5 for LINQ, but they’re also very useful in your own classes. Action<> allows you to specify types for up to 4 parameters and returns void, and Func<> does the same except you can also specify a return type. if you look at the LINQ extension methods, you’ll see these delegates extensively.

so for example, if you needed a delegate that returned void and took no parameters, you’d have to write something like:

public delegate void VoidDelegate();

public event VoidDelegate MyEvent;

so what you end up with is repetitive declarations of such a VoidDelegate delegate in lots of classes. now, you can just use the Action<> delegate to do this (Action<> works in any case where you return void and take up to 4 parameters):

public event Action MyEvent;

same goes for Func<>. before, you’d have to create a delegate for each specific set of input variable and return types:

public delegate string TakeTwoStringsAndReturnStringDelegate(string String1, string String2);

and then call it like:


return (String)Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
(TakeTwoStringsAndReturnStringDelegate)delegate
{
return TakeTwoStringsAndReturnString("1", "2");
}
);

now you can use Func<> instead (Func<> also works for up to 4 parameters):

return (String)Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
(Func<String, String, String>)delegate
{
return TakeTwoStringsAndReturnString("1", "2");
}
);

there are probably still times when you’ll want to create your own delegate, but these two generics are very useful for filling in the gaps—

2 comments:

I. J. Kennedy said...

Sorry I'm so late to the party as far as Action delegates. I tried your sample line

public event Action MyEvent;

but got an error:

Using the generic type 'System.Action<T>' requires '1' type arguments

Did MS do away with Actions that take no parameters?

raulgspan said...

hmmmm, not sure why you're seeing that. there are System.Action Delegate signatures that take 0, 1, 2, 3, and 4 parameters (as shown here: http://msdn.microsoft.com/en-us/library/system.action.aspx, http://msdn.microsoft.com/en-us/library/system.action.aspx, http://msdn.microsoft.com/en-us/library/bb549311.aspx, etc.). if you create a brand new .NET 3.5 WPF application and replace your Window1.xaml.cs code with this code, does it compile? works properly for me:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
public partial class Window1 : Window
{
public event Action MyEvent;

public Window1()
{
InitializeComponent();

this.MyEvent += new Action(Window1_MyEvent);

this.MyEvent();
}

void Window1_MyEvent()
{
MessageBox.Show("My Event");
}
}
}