Extension methods, what you shouldn't do
I’ll admit it, I love extension methods, especially the ones from the LinQ-to-objects framework.
However I often see them abused, partly by making everything extension methods, and partly by breaking readability with methods which normally shouldn’t work.
The latter requires an example, obviously:
public static bool IsNullOrEmpty(this string str)
{
return string.IsNullOrEmpty(str);
}
What’s wrong with the above, you may wonder ? Well when using it it’ll look like this:
string name = null;
if (!name.IsNullOrEmpty())
Console.WriteLine(name);
Normally calling a method on a null object will throw a NullReferenceException, and rightly so!
Reading the above you’d think: this’ll break. You’d have to dig into the IsNullOrEmpty extension method, in order to understand that it doesn’t break.
Now assume that the extension method resides in a 3rd party DLL, so you haven’t got the source code… You’d have to test the method, or simply avoid it – either way is bad.
Finally, how much did you actually gain by writing foo.IsNullOrEmpty() instead of string.IsNullOrEmpty(foo) ? Exactly 6 letters! (“string”).
Bottom-line: Don’t do this 🙂
After this rant, I’ll show you some extension methods I wrote and use frequently (most are for ASP.Net):
ToHashSet
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> items)
{
return new HashSet<T>(items);
}
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> items, IEqualityComparer<T> comparer)
{
return new HashSet<T>(items, comparer);
}
I for one don’t understand why this isn’t included in the LinQ-to-objects framework, as it already has ToList, ToArray and ToDictionary.
It’s used the same way as the other ToFoo methods:
var usernames = users
.Select(user => user.Name)
.ToHashSet();
IsItem
public static bool IsItem(this RepeaterItemEventArgs e)
{
return (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item);
}
public static bool IsItem(this DataListItemEventArgs e)
{
return (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item);
}
This one really shortens the check for ItemType inside ItemDataBound events of the respective repeating controls.
protected void repUsers_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (!e.IsItem())
return;
// As opposed to
if (e.Item.ItemType != ListItemType.AlternatingItem && e.Item.ItemType != ListItemType.Item)
return;
}
FindControl
public static T FindControl<T>(this RepeaterItemEventArgs e, string id) where T : Control
{
return (T)e.Item.FindControl(id);
}
public static T FindControl<T>(this DataListItemEventArgs e, string id) where T : Control
{
return (T)e.Item.FindControl(id);
}
A nice shortcut to the somewhat hideous syntax you’d otherwise use for setting e.g. Literals’ Text inside ItemDataBound events:
protected void repUsers_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var user = (User)e.Item.DataItem;
e.FindControl<Literal>("litName").Text = user.Name;
// As opposed to
((Literal)e.Item.FindControl("litName")).Text = user.Name;
}
And that’s it, notice how few I have – Either I’m missing out on something, or everything doesn’t have to be an extension method – what do you think ?
Also if you’ve got any nice extension methods up your sleeve, feel free to share them with me 🙂 (Dropping a comment)