Extracting the Func

Recently, I’ve found myself using Generic Delegates quite a lot, and in particular the Func<> delegate. Delegates can be a great way of reducing duplication and increasing code re-use.

The following is a rather contrived example, and mostly useless, but it helps to illustrate the process of what I like to call “Extracting the Func”

Say you have a method that writes to the console, the result of adding two numbers together:


public void WriteResultOfCalculation(int x, int y)
{
     Console.Write((x + y).ToString());
}

But then, u decide you want similar functionality, but instead of adding x and y you want to multiply x and y (besides obvious ways of doing this) you could extract the calculation into a Func delegate like this:


public void WriteResultOf(Func<int, int, string> calculation)
{
     Console.Write(calculation);
}

WriteResultOf((x,y) => (1 * 2));

Here we have pushed the responsibility of performing the calculation to the consumer. This code is quite useless, but I’ve intentionally used this example so not to distract from the point.

The next example of this pattern, hopefully, shows how this can be useful. A few weeks ago, I was working with a repeater control in an asp.net site. The repeater contained a usercontrol with multiple grids and I needed easy access to manipulate every instance of this usercontrol in the repeater. So I whipped up a quick extension method for Repeater controls modeled on the IList ForEach extension:


        public static void ForEach<TControl>(this Repeater repeater, Action<TControl> action) where TControl : Control
        {
            foreach (RepeaterItem item in repeater.Items)
            {
                foreach (Control control in item.Controls)
                {
                    Repeater nestedRepeater = control as Repeater;
                    if(nestedRepeater != null)
                    {
                        nestedRepeater.ForEach(action);
                    }

                    TControl t = control as TControl;
                    if(t != null)
                    {
                        action(t);
                    }
                }
            }
        }

This method has a type parameter of TControl, which is constrained to types derived from “Control”. This is the type of the control that you are wishing to gain access to, within the repeater. It iterates the RepeaterItems of the repeater, and nested in this, it iterates the controls of each RepeaterItem. Within the nested loop, it first performs a safe cast to typeof(Repeater), and performs a recursive call if the cast is successful. Finally, a safe cast is performed to TControl, and if successful it calls the Action delegate, passing in the instance of TControl as the argument.

In a nutshell, it performs recursion to find all instances of the type TContol within the repeaters nested controls, then performs the action, specified by the consumer, on the control.

The signature of Action is a method that accepts a paramter of type TControl and returns void:


void Action(TControl control);

As the ForEach is modelled on ILists ForEach, its usage should be fairly intuitive. For example, lets say the control we are after has a public method “LoadReport”, and we’d like to call this method for each instance inside the repeater, we can call it like this:

    repeater.ForEach(control => control.LoadReport());

Piece of cake. Now as I wasn’t happy leaving this nested loop, essentially hiding the intent of code, I’ve refactored it a little, breaking down into 4 smaller methods:

        public static void ForEach<T>(this Repeater repeater, Action<T> action) where T : class
        {
            repeater.ForEachNestedRepeater(action);
            foreach (T t in repeater.GetItemsOfType<T>())
            {
                action(t);
            }
        }

        private static void ForEachNestedRepeater<T>(this Repeater repeater, Action<T> action) where T : class 
        {
            repeater.GetItemsOfType<Repeater>()
                    .ForEach(r => r.ForEach(action));
        }

        private static IEnumerable<T> GetItemsOfType<T>(this Repeater repeater)
        {
            return repeater.Items.Cast<RepeaterItem>()
                                 .Select(item => item.Controls)
                                 .OfType<T>();
        }

        private static void ForEach(this IEnumerable<Repeater> repeaters, Action<Repeater> action)
        {
            foreach (var repeater in repeaters)
            {
                action(repeater);
            }
        }

Happy coding!