I think that ASP.NET MVC is a huge step forward from ASP.NET Web Forms. Still, there are some parts of it that are disappointing. One is the SelectList
constructor, that doesn’t use generics and has string parameters for field selection. To create a SelectList
from an IEnumerable<>
we would do something like this.
IEnumerable<Person> people = GetPeople(); SelectList selectList = new SelectList(people, "Id", "FullName"); |
This is again one of those places where the compiler won’t be able to help us. Writing member names as strings in the code is just horrible. To remedy this I wrote a factory method with those strings changed into lambdas.
IEnumerable<Person> = GetPeople(); SelectList selectList = people.ToSelectList(people, p => p.Id, p => p.FullName); |
ToSelectList Extension Method
The ToSelectList
method extracts the member names from the lambdas and then calls the normal SelectList
constructor. Thanks to the ExpressionHelper.GetExpressionText
helper method the code is short.
public static SelectList ToSelectList<TSource, TValue, TText>( this IEnumerable<TSource> source, Expression<Func<TSource, TValue>> dataValueField, Expression<Func<TSource, TText>> dataTextField) { string dataName = ExpressionHelper.GetExpressionText(dataValueField); string textName = ExpressionHelper.GetExpressionText(dataTextField); return new SelectList(source, dataName, textName); } |
ToSelectList
is a generic extension method that takes three parameters.
source
is theIEnumerable<TSoudce>
that contains the elements.dataValueField
is a lambda expression selecting the member that is the value field.dataTextField
is a lambda expression selecting the member that is the text field.
The ExpressionHelper.GetExpressionText
from System.Web.Mvc
extracts the field name from the lambda expression and then sends the retrieved string into the SelectList
constructor. No more string constants referring to member names. Any typos or missed updates will now be caught during compilation.
Members as strings in code are not evil by itself, the problem is missing tooling support. If compile time errors, intellisense, refactoring, find all members etc were in place it would be no problem at all.
It’s a somewhat less risky way than using the bare
SelectList
constructor. The Key and Value fields will hardly change names, while there is a larger risk that thePerson
fields changes.My concerns are more about going over a
Dictionary
. One consideration is the performance cost of creating a dictionary. Another is the sorting. Isn’t there a risk that any order served byGetPeople
will be lost when going over the dictionary?About performance, how many object does the ExpressionHelper.GetExpressionText() method create? I bet more than one.
About sorting, ToDictionary() creates a Dictionary which does not change the order of items.