tags:

views:

369

answers:

7

Today I finally "got" the Func<> delegate and saw how I could use it to make some of my less readable LINQ queries (hopefully) more readable.

Here's a simple code sample illustrating the above, in a (very) trivial example

List<int> numbers = new List<int> { 1, 5, 6, 3, 8, 7, 9, 2, 3, 4, 5, 6, };

// To get the count of those that are less than four we might write:
int lessThanFourCount = numbers.Where(n => n < 4).Count();

// But this can also be written as:
Func<int, bool> lessThanFour = n => n < 4;

int lessThanFourCount = numbers.Where(lessThanFour).Count();

Can anyone else give any examples of scenarios where they use Func<>?

(Note that I would not advocate using Func<> in a scenario as simple as that shown above, it's just an example that hopefully makes the functionality of Func<> clear.)

A: 

Most of the time NOT.

Koistya Navin
Because I usially don't reuse functions since most likely they are different each time.
Koistya Navin
+1  A: 

I usually only do it when I want to reuse the delegate. Otherwise, not often.

Razzie
+5  A: 

I guess there would only be a point in doing this if you were going to be reusing the Func in question in a number of places (and it involved more than trivial logic). Otherwise using the standard way seems much better and perfectly readable.

Rob West
+3  A: 

It's only really more readable/useful when/if you are reusing it.

A more interesting Lambda to pass around and futz with, would be Expression<Func<int,bool>> as you can still invoke it when you want too, but you can also pull it completely apart and tinker with it.

Its...well...dead sexy.

Tim Jarvis
Tim - could you add a nice little example of using Expression<Func<int, bool>>?
Richard Ev
I'll see what I can knock up (something simple) but in the meanwhile for your amusement here is something seriously cool that Bart De Smet did. http://community.bartdesmet.net/blogs/bart/archive/2009/02/10/linq-and-the-matrix-introducing-mlinq.aspx
Tim Jarvis
+2  A: 

I am using the Func and Action delegates for a common handling of exceptions. I often find myself building the same try-catch block over and over again, because I keep them as short as possible. Delegate and Action can reduces the try-catch code duplication.

A really simple example would be:

...    
DoSomethingPotentiallyBad((x) => x * 2, 0); // both delegates do
DoSomethingPotentiallyBad((x) => 2 / x, 0); // something different ... 
...

    static int DoSomethingPotentiallyBad(Func<int, int> function, int input)
    {
      // ... but get exception handled all the same way  
      try
        {
            return function.Invoke(input);
        }
        catch
        {
            Console.WriteLine("Evaluation failed! Return 0.");
            return 0;
        }
    }

This example is very artificial and doesn't show the power of it. But supposed that you have something like database operations instead and you want to retry each failing database operation 5 times (which involves using flags, a finally-block and a while loop) and want the same application-wide logging, then you have just one place to put that try-catch block: It's the method, which takes a Func or Action delegate as argument. Code which handles business logic is almost free of those try-catch-blocks and thus are more readable.

For some more advance example and longer description have a look at: Action Policy

Theo Lenndorff
+1  A: 

How about accepting a Func<> parameter in your own methods, when appropriate, to make them more flexible and extensible? For example:

public static string ToDelimitedString<T>(
    this IEnumerable<T> source, Func<T, string> converter, string separator)
{
    // error checking removed for readability

    StringBuilder sb = new StringBuilder();
    foreach (T item in source)
    {
        sb.Append(converter(item));
        sb.Append(separator);
    }

    return (sb.Length > 0) ?
        sb.ToString(0, sb.Length - separator.Length) : string.Empty;
}

// ...

List<int> e1 = new List<int> { 1, 2, 3 };
// convert to "2|4|6"
string s1 = e1.ToDelimitedString(x => (x * 2).ToString(), "|");

DateTime[] e2 = new DateTime[]
    { DateTime.Now.AddDays(-100), DateTime.Now, DateTime.Now.AddDays(100) };
// convert to "Tuesday, Thursday, Saturday"
string s2 = e2.ToDelimitedString(x => x.DayOfWeek.ToString(), ", ");

List<MyCustomType> e3 = new List<MyCustomType>
    { new MyCustomType("x"), new MyCustomType("y"), new MyCustomType("z") };
// convert to "X and Y and Z"
string s3 = e3.ToDelimitedString(x => x.Name.ToUpper(), " and ");
LukeH
I would rewrite the body of this as: return string.Join( separator, source.Select(converter).ToArray());
Keith
@Keith, Using string.Join is slower than a StringBuilder - In my tests it's about 10% slower for small collections, rising to as much as 50% slower for larger collections.
LukeH
@Keith, The string.Join version is, however, more readable than using a StringBuilder, and it's probably plenty fast enough for most situations.
LukeH
A: 

Thanks it's enlighting.

JPMarichal