Are extensive extension method an anti-pattern
November 30th 2009I was explaining my dilemma to a Java friend and the e-mail ended up being fairly interesting, so I thought I would share it.
I’m sure Java has extension methods, but I’ll give it a once over just in case. You can extend existing classes without sub-classing by extension methods.
public static IEnumerable<SelectListItem>AsSelectListItems( this IEnumerable<Person> listOfPeople){IList<SelectListItem> selectListItems = new List
(); foreach(var person in listOfPeople){ selecListItems.Add(new SelectListItem(person.ID, string.Format("{0} {1} {2}", person.First, person.Middle, person.Last));} return selectListItems; }
Right. So the
thisoperator tells the compiler to basically create this function:
public static IEnumerable<SelectListItem>AsSelectListItems(IEnumerable<Person> listOfPeople);</pre>
And invoke it every time you see this:
IEnunerable<Person> p = myService.GetAllPeople(); IEnumerable<SelectListItem> s = p.AsSelectListItems();
You probably knew all this, but it explains how we are using them. We end up calling a lot of extension methods off other extension methods.
myViewData.PersonSelectListItems = myService.GetAllPeople().AsSelectListItems() .OrderedByText() .StartingWithAnEmptyItem();</pre>
In this example we have three extension method calls and I think it really makes the code much more readable, but it makes testing this code a little more difficult. Obviously, the myService is a mocked dependency which will return a fake list of people, but the other extension method calls cannot be mocked, and the scope of the test bleeds a bit.
I like the syntax it gives, but now I’m going to test potentially four classes when I should be testing only one.
This gets pretty pandemic in our code. Especially trying to make Seleniums API and the assertion API of Nunit and xUnit more fluent.