Enhancing code readability

I'm a big fan of easily readable code, in fact, my appreciation for code that reads almost English has only grown over the years. Extension methods in C# allow for some nice tricks to take place in this regard.


I first saw the notation "1.Seconds()" in Fun with extension-methods (and similar notations for the DateTime class in DateTime extensions), and have since played around with it myself to be able to write things like "myDateTime.IsBefore(1.Hours().Ago())" instead of mathematically manipulating TimeSpans and DateTimes to death.

This time I'd like to share another C# fun fact that has to do with readability - conversions between method groups and delegates.

Suppose we have the following method:

/// <summary>
/// Creates and starts a timer that performs an action upon each time an interval elapses.
/// </summary>
/// <param name="interval">The interval that will be configured for the created timer.</param>
/// <param name="uponTimerElapsed">The action to be performed by the counter.</param>
/// <returns>The timer instance created.</returns>
public Timer GetPeriodicTimer(TimeSpan interval, Action uponTimerElapsed)
{
var timer = new Timer(interval.TotalMilliseconds) { AutoReset = true };
timer.Elapsed += (sender, args) => uponTimerElapsed();
timer.Start();
return timer;
}
(One could even go further and have it like so:

/// <summary>
/// Creates and starts a timer that performs an action upon each time an interval elapses.
/// </summary>
/// <param name="interval">The interval that will be configured for the created timer.</param>
/// <param name="uponTimerElapsed">The action to be performed by the counter.</param>
/// <returns>The timer instance created.</returns>
public static Timer GetPeriodicTimer(this TimeSpan interval, Action uponTimerElapsed)
{
var timer = new Timer(interval.TotalMilliseconds) { AutoReset = true };
timer.Elapsed += (sender, args) => uponTimerElapsed();
timer.Start();
return timer;
}
// usage:
var oneSecondTimer = 1.Seconds().GetPeriodicTimer(...);
I'd say it's a bit overextending, pardon the pun, but that's a matter of personal taste I suppose.)

A trivial usage of GetPeriodicTimer would be:

var oneSecondTimer =
GetPeriodicTimer(
1.Seconds(),
new Action(MyActionMethod1));
However, since there is an implicit conversion between method groups and delegates you can let the compiler do the thinking:

var oneSecondTimer =
GetPeriodicTimer(
1.Seconds(),
MyActionMethod1);
Imagine a scenario where you'd like to have two actions invoked whenever the timer elapses. You could, of course, create a separate method and invoke your two actions from within, but that seems a bit off. We'd probably want to write something like:

// wrong, will NOT compile
var oneSecondTimer =
GetPeriodicTimer(
1.Seconds(),
MyActionMethod1 + MyActionMethod2);
However, this is the point where the compiler won't play ball and remind you that after all, you're using method groups, not actual delegates, and since the '+' operator is undefined for method groups, things go bad.

In order for the compiler to pick up on what's going on, all we need is to explicitly convert one of the method groups to an action (any of the two will do the trick):

var oneSecondTimer =
GetPeriodicTimer(
1.Seconds(),
new Action(MyActionMethod1) + MyActionMethod2);
Now the '+' operator has a delegate as the left hand operand and a method group as the right side operand - which it can automatically (and implicitly) convert to an action. Since the '+' operator is well defined for delegates, we're off the hook.

Another benefit is that further actions can be added as method groups as well:

var oneSecondTimer =
GetPeriodicTimer(
1.Seconds(),
new Action(MyActionMethod1) + MyActionMethod2 + MyActionMethod3);
Though if you have more than just a few, it's probably best to extract them to a separate method after all, for the sake of... well, enhancing code readability.

Comments

Popular posts from this blog

Eclipse vs. IntelliJ, an empirical rant