.net, C# tip, Clean Code

C# tip – specifying Optional parameters and clean code

I’ve recently been writing an API, and on one of the method overloads I needed to include a couple of optional attributes.

I knew this was possible in C# 4.0, and found that the canonical way of implementing this is to use the pattern below.

private static string EditorFor<TModel, TSelectedValue>(
    this HtmlHelper htmlHelper,
    Expression<Func<TModel, TSelectedValue>> formFieldName,
    string optionLabel = null,
    object htmlAttributes = null)
{
    // ...
}

This pattern makes sense to me for assignation of a default value to the parameter, but less sense as a way to indicate the parameter is optional.

I guess that once you’re used to seeing the pattern you learn to recognize it, but it doesn’t really convey the intent of the API.

After a little digging, I found that this isn’t the only way to indicate an optional parameter, and – in my opinion – the [Optional] parameter attribute more clearly demonstrates how I (as the API author) intended the method to be used:

private static string EditorFor<TModel, TSelectedValue>(
    this HtmlHelper htmlHelper,
    Expression<Func<TModel, TSelectedValue>> formFieldName,
    [Optionalstring optionLabel,
    [Optionalobject htmlAttributes)
{
    // ...
}

You can read more on MSDN about optional arguments here and the OptionalAttribute class here.

.net, C# tip, Clean Code

C# tip – When to return IEnumerable instead of IList (and when not to)

I think it’s now almost mandatory for every tech blog to deal with this question.

There’s a received wisdom that it’s always better to return the most specific interface – meaning the interface which has the smallest possible set of functions. By that token, since IEnumerable<T> is smaller than IList<T> you should return IEnumerable<T>. You can’t predict that the user will need to use things that IList<T> offers (like the Count() method) because you don’t know that they’re going to need it.

I can see how this makes sense.

There’s also a counterpoint that says you should return the most functionally rich interface – so instead of returning an interface which has nothing but GetEnumerator, give your consumer something that will be immediately useful to them – for example, IList has a Count() method, or allows them to retrieve elements at a specific index. It’s cheap for the developer and it might add value for the user.

Whatever is right for you, is right for you – most articles that I’ve read come down on the site of IEnumerable<T>, but it’s not cut and dried.

My personal preference is to go with the smallest possible interface. It makes sense for me because if I need to change my return type later, it’s easy to go from IEnumerable<T> to (say) ICollection<T> and know my public API consumer’s code will continue to work.

That logic doesn’t work the other way around. Say I have the following code:

private static IList<SelectListItem> ConvertListItemsToSelectList(IEnumerable<User> users)
{
    var userSelectList = new List<SelectListItem>();
 
    foreach (var user in users)
    {
        userSelectList.Add(
            new SelectListItem { 
                Value = user.Id.ToString(), 
                Text = user.Name 
            });
    }
 
    return userSelectList;
}

At some future point, I may want to change this code to use the yield keyword, as below:

private static IEnumerable<SelectListItem> ConvertListItemsToSelectList(IEnumerable<User> users)
{
    foreach (var user in users)
    {
        yield return new SelectListItem { 
            Value = user.Id.ToString(), 
            Text = user.Name 
        };
    }
}

The code is shorter, cleaner, declares fewer variables, and frustratingly I can’t use it because I have to change my return type to IEnumerable<SelectListItem>. If one of my users has performed a Count() operation on the original version of ConvertListItemsToSelectList, their code will no longer compile with my latest change. Going for IEnumerable<SelectListItem> in the first place would have been a better choice.

I guess if it was a privately used API, which I knew was never going to change, I might feel differently. As with so much in software craftsmanship, it’s about picking the right tool for the job at hand.

You can read more about the IList interface on MSDN here.

You can read more about the ICollection interface on MSDN here.

You can read more about the IEnumerable interface on MSDN here.