Func<T> vs. Action<T>

Methods…

Although I’ve been using Func<T> and Action<T> for years, I’m embarrassed to say I hadn’t really thought about the differences between them – or more importantly, how they are in fact two sides of the same coin.

Most of the time their use has been a natural reflex action to a coding problem, and the consideration of the other method hasn’t even entered my mind. It’s time I also start using their proper names, which also belies their use:

 

Action<T>

and

Func<TResult>

 

Today’s Problem

I needed a way of enumerating a directory of files and executing a bit of arbitrary code against each one. The code that was to be executed needed the contents of the file. So I instincively wrote something like the following:

 

// Scan files
public void ScanFiles(string path, Func<string, void> codeToExecute)
{
    foreach(string filename in System.IO.Directory.GetFiles(path))
    {
        string fileContents = "";
        using(System.IO.FileStream fileStream = System.IO.File.Open(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read)) 
        {
            using(System.IO.StreamReader streamReader = new System.IO.StreamReader(fileStream))
            {
                fileContents = streamReader.ReadToEnd();
            } // Close stream
        } // Relinquish handle to file

        // Execute the code and pass the contents of the file
        codeToExecute(fileContents);
    }
}

 

But of course, anyone with half a second of experience writing anonymous functions (or just any .NET experience) will know you can’t use “void” as a return type for a generic. I can only blame the fact that it was late in the day, but it took me about 5 minutes to figure out why using

 

Func<string, void>

 

wasn’t allowing me to return void. Of course there is a generic you can use: I should have used Action<string> instead. Action<T> doesn’t require you to define the return type. In fact, you can’t define a return type for Action<T>. (That’s what Func<TResult> is for!

If anybody’s new to this stuff, you can use the following code to give an anonymous function to this method above, which will be given the file’s contents to process:

 

public void ProcessDirectory (string path)
{
    // Call the ScanFiles method, passing in the directory path, and also an anonymous function
    // which shows a message box containing the contents of the file.
    // (Not realistic, but you get the point).
    ScanFiles(path, (contentsOfFile) => {
                   // Do something with the contents of the file
                   MessageBox.Show(contentsOfFile);
    });
}

 

 

Conclusion: The Differences

Func<TResult> lets you pass in an anonymous method which returns the type of TResult. You can also define a Func which takes multiple parameters like this:

 

Func<T1,T2,T3,...,TResult>

 

Meanwhile, Action<T> wont return you anything, but you can define an Action that takes multiple inputs using a similar syntax the the code just above.

 

Action<T1,T2,T3,...>

 

I like anonymous functions. They remind me very much of JavaScript. And JavaScript is the Language of the Gods!*

 

* probably not true…  But it should be!!!!

 

Leave a Comment