Type Safe SelectList Factory

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.

  1. source is the IEnumerable<TSoudce> that contains the elements.
  2. dataValueField is a lambda expression selecting the member that is the value field.
  3. 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.

  • Albin Sunnanbo on 2012-01-24

    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.

  • Max Toro on 2012-05-15

    var peopleOptions = GetPeople().ToDictionary(p => p.Id, p => p.Name);
    var selectList = new SelectList(peopleOptions, "Key", "Value");

    • Anders Abel on 2012-05-15

      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 the Person 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 by GetPeople will be lost when going over the dictionary?

      • Max Toro on 2012-05-21

        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.

  • Leave a Reply

    Your name as it will be displayed on the posted comment.
    Your e-mail address will not be published. It is only used if I want to get in touch during comment moderation.
    Your name will be a link to this address.
Software Development is a Job – Coding is a Passion

I'm Anders Abel, an independent systems architect and developer in Stockholm, Sweden.

profile for Anders Abel at Stack Overflow, Q&A for professional and enthusiast programmers

Code for most posts is available on my GitHub account.

Popular Posts

Archives

Series

Powered by WordPress with the Passion for Coding theme.