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 simpl
I usually only do it when I want to reuse the delegate. Otherwise, not often.
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
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.
Most of the time NOT.
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.
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 ");