I’ve become a fan of using named parameters for adding expressiveness to code that could otherwise be ambiguous. You could argue that there are better approaches for increasing code readability, but sometimes a named parameter can go a long way. For instance, the intention of the following code is pretty obvious (or should be) to someone reading it:

var grid = new WebGrid(canSort: false,
                        rowsPerPage: 10)
                .Bind(autoSortAndPage: false,
                        source: data,
                        rowCount: count);

In the case of the WebGrid’s constructor (and its Bind function), named parameters are typically needed because it contains a handful of optional parameters that you usually don’t override, but ordinaly precede the ones you do (as is the case with my example above). But, even if canSort and rowsPerPage were the only parameters in the WebGrid class’ constructor, I might still name them for clarity. Either way, that’s besides the point.

The nice thing about named/optional parameters is that parameter ordinality no longer matters. You can omit and rearrage parameters within your method calls to whatever is most intuitive for you. For instance, I like the approach the ASP.NET team has taken with their web helpers (e.g. WebGrid), in which they favor large parameter count method signatures where every parameter (or most of them) is optional. That way your calling code can be as simple or complex as you want/need it to be and you can name your parameters and order them however you please.

For instance, when generating the HTML for my above WebGrid, I could simply call:

grid.GetHtml()

Or I could get much fancier and do:

grid.GetHtml(mode: WebGridPagerModes.NextPrevious,
            htmlAttributes: new { id = "error-list" }, 
            columns: grid.Columns(
            grid.Column(format: @<text>
                                    <a title="View Details" href="Href("@/ErrorLog/" + item.Id)"><span>View Details</span></a>
                                    <a title="Clear" href="Href("@/ErrorLog/" + item.Id)/Delete"><span>Clear</span></a>
                                </text>),
            grid.Column("Time", "Date/Time"),
            grid.Column("ExceptionTypeName", "Type"),
            grid.Column("Message"),
            grid.Column("Cookies?", format: @DisplayYesNo(item.Cookies)),
            grid.Column("Form?", format: @DisplayYesNo(item.Form)),
            grid.Column("Query?", format: @DisplayYesNo(item.QueryString))))

All of this works great and is a pretty slick pattern for doing these kind of “helpers”. But, a wrench gets thrown into the works when using this pattern in a very specific scenario: if your method takes a generic delegate (e.g. Func<T>, Action<T>) as a parameter, and you’d like your consumers to be able to leverage type inference.

Let me state that another way: if you have a generic method that takes a generic delegate as a parameter, your consumers have to choose between using named parameters and type inference. Both won’t work in this context.

NOTE: I say “generic method” because if a method took a generic delegate as a parameter, but the generic type was coming from the containing class (e.g. public class Whatever<T>), then type inference on the method wouldn’t be necessary.

To see what I mean, let’s look at an example. Imagine you have the following method (it’s a method for creating an RSS and Atom feed based on some application data):

public static void Register<T>(string rootUrlName, string title, Func<IEnumerable<T>> entryData, Func<T, FeedEntry> entryMapper, string description = "")

Here we’ve introduced generic delegates as parameters to a generic method. We also have an optional parameter. Calling it to create a feed of static People data could look something like this:

Register<Person>("",
    "People Feed",
    () => new[] {
        new Person { FirstName = "Jonathan", LastName = "Carter" },
        new Person { FirstName = "Drew", LastName = "Robbins" }
    },
    (p) => new FeedEntry {
        Title = p.FirstName + p.LastName,
        Content = "This person needs to be described better!"
},
"This is a feed of people);

We’re explicitly setting the generic type parameter and aren’t using named parameters, so everything works as expected. As the consumer of this method, though, I might decide to use named parameters here, which would then look like this:

Register<Person>("",
    title: "People Feed",
    description: "This is a feed of people",
    entryData: () => new[] {
            new Person { FirstName = "Jonathan", LastName = "Carter" },
            new Person { FirstName = "Drew", LastName = "Robbins" }
        },
        entryMapper: (p) => new FeedEntry {
            Title = p.FirstName + p.LastName,
            Content = "This person needs to be described better!"
});

Notice that I moved the description parameter up in the order, since I find that to be more readable. Named parameters allowed me to do this, and is a small little improvement that I love using sometimes.

Now, I might also decide to “clean” this up a bit further and allow the C# compiler to infer the type parameter. After all it should be smart enough to know, based on the value I’m passing to entryData, that T should be Person. But, if I write the following, I’ll get an error:

Register("",
    title: "People Feed",
    description: "This is a feed of people",
    entryData: () => new[] {
            new Person { FirstName = "Jonathan", LastName = "Carter" },
            new Person { FirstName = "Drew", LastName = "Robbins" }
        },
        entryMapper: (p) => new FeedEntry {
            Title = p.FirstName + p.LastName,
            Content = "This person needs to be described better!"
});

The reason this doesn’t work is because of the fact that I’m using named parameters, type inference and generic delegates all at the same time. If I removed the named parameters from the above, it would work:

Register("",
    "People Feed",
    () => new[] {
        new Person { FirstName = "Jonathan", LastName = "Carter" },
        new Person { FirstName = "Drew", LastName = "Robbins" }
    },
    (p) => new FeedEntry {
        Title = p.FirstName + p.LastName,
        Content = "This person needs to be described better!"
    },
    "This is a feed of people");

This proves I can choose between type inference or named parameters, but not both. Unfortunately, you’ll notice that I had to move the description parameter back to the end of the parameter list, because without being able to use named parameters, I can’t rearrange the defined ordinal.

Why is this the case though? Before explaining that, let’s clarify how type inference in general works. When I defined the Register<T> method above, it just so happened that some of its parameters also made use of the generic type parameter T. What that means is that as long as the T can be determined from the parameter value, it can also be inferred for the entire method, which allows us to not explicitly pass it (e.g. Register<T> vs. just Register). If none of the method parameters make use of the generic type parameter then type inference wouldn’t be possible, since the compiler would have no way of determining it.

This is a pretty slick feature, and is why the sample code above works without specifying the generic type parameter explicitly. The lambda that I pass to the entryData parameter tells the compiler that the T generic type parameter should be set to Person. Subsequently, because the next parameter (entryMapper) also makes use of the T generic type parameter, the compiler now knows that T is of type Person, so you’d get intellisense within the lambda.

This type inference behavior works great regardless whether you’re specifying your parameter list ordinaly or named, except when there is a generic delegate parameter. Moreover, even if you pass the parameters in the defined order, but name them, type inference still won’t work (our example above proved this).

There is a slight caveat to this rule, as can be seen below (I’m now omiting the description parameter):

Register("",
    "People Feed",
    () => new[] {
        new Person { FirstName = "Jonathan", LastName = "Carter" },
        new Person { FirstName = "Drew", LastName = "Robbins" }
    },
    entryMapper: (p) => new FeedEntry {
        Title = p.FirstName + p.LastName,
        Content = "This person needs to be described better!"
    });

This proves that named parameters, generic delegates and type inference can kind of work together. If I tried to name any of the first three parameters, though, the code would once again be broken. This clarifies that once the type has been inferred from a parameter value, all subsequent parameters (even generic delegates) can now be named.

NOTE: This constraint only exists for generic delegates. If your generic method takes other generic types (e.g. IEnumerable<T>), you can successfully use type inference and named parameters together as flexibly as you please. It’s only when using generic delegates that you have to choose.

Beyond understanding why this constraint exists, it still provides a limitation for designing a clean/simple API. For instance, I want the Register function to be generic in order to provide intellisense for callers when setting the lambda expression parameters, but I also want it to be used in dynamic scenarios where a type isn’t known (or needed). You could argue that a developer could simply call the method as Register<dynamic>, and you’d be right, but that code seems unnecessary for the consumer. In addition, that doesn’t help in situations where the inferred generic type is an anonymous type and you want intellisense for subsequent parameters, like so (notice I’d get intellisense in the fourth parameter on the p variable):

,
Register("",
    "People Feed",
    () => new[] {
        new { FirstName = "Jonathan", LastName = "Carter" },
        new { FirstName = "Drew", LastName = "Robbins" }
    },
    (p) => new FeedEntry {
        Title = p.FirstName + p.LastName,
        Content = "This person needs to be described better!"
    });

What would the user specify as the generic type here? This is a scenario where type inference becomes very useful. Imagine how nice that code would look with named parameters as well. It’d be beautiful :)

So how could I support the caller for being able to leverage…

  1. Explicit generic type declaration with named parameters
  2. Explicit generic type declaration without named parameters 
  3. Generic type inference without using named parameters
  4. Generic type inference with named parameters

The first three items are already satisfied by our existing Register<T> method, but the fourth isn’t. I could satisfy all four by removing the generic type parameter and changing all occurrences of T in the parameter type definitions to dynamic, but then I’d completely lose intellisense in scenarios where a type could be inferred (that wouldn’t be type inference then). Therefore, how can I allow all four scenarios, without completely giving up intellisense for the developer? Unfortunately, you can’t. Item #4 just won’t work with the current C# compiler. It’s a bug.

Hence, if you’re designing an API that uses generic methods, that take generic delegates as parameters, and you want your users to be able to use type inference (needed for anonymous types), you’ll need to make sure that named parameters aren’t necessary to add expressiveness, since they won’t be usable, unless the parameter that can infer the type is very early on in the method signature’s parameter order. This means that a method with optional parameters (where named parameters become common), that uses generic delegates, can’t take advantage of type inference unless the caller specified every optional parameter and didn’t use named parameters, which is a pretty poor expectation.

Where applicable, a method chaining API (a.k.a. fluent API) could be a great option for creating additional expressiveness for your users without sacrificing any type inference or intellisense. Unfortunately, though, sometimes a fluent API is overkill for a scenario (e.g. a helper function), or less intuitive, so you’re stuck dealing with the named parameters/type inference limitation.

This is a pretty niche limitation (generic method + generic delegate parameter + named parameters + type inference), and probably won’t occur very often for folks designing APIs, but when it does, hopefully this post will help you from wanting to pull your hair out from wondering what the issue is. When all else fails: just explicitly declare your generic type parameters. I’d rather do that than give up named parameters :)