Using C# 3.0 Anonymous Types as Dictionaries

During a design meeting for a new feature in ASP.NET we had a requirement that a new method accept a dictionary of name/values pairs. An obvious solution is to have the method accept a parameter of type IDictionary (or its generic cousin):

public static string GetHtmlLink(string text, IDictionary<string, string> properties) {
...
}

While it looks nice and neat from the perspective of our function, the caller of this function has a real mess to deal with. Creating dictionaries is definitely somewhat of a pain. Since Dictionary<TKey, TValue> doesn't have an Add() method with one parameter you can't use C# 3.0's collection initializer syntax. This is some ugly code:

Dictionary<string, string> values = new Dictionary<string, string>();
values.Add("key1", "value1");
values.Add("key2", "value2");
values.Add("key3", "value3");
GetHtmlLink("Click me", values);

My proposal: Have the method accept a parameter of type object. Callers could pass in a type that has properties with the appropriate names and values. They can use C#'s object initializer syntax to save some space:

MyParams myParams = new MyParams { Key1 = "value1", Key2 = "value2", Key3 = "value3" };
GetHtmlLink("Click me", myParams);

However, there was the added work of defining the MyParams type. Admittedly, it wasn't that hard with C# 3.0's automatic properties, but I hate defining types that are used in only one place. If the user can pass in an arbitrary object with properties, why not let that object be of an anonymous type? Here's the final code:

GetHtmlLink("Click me", new { Key1 = "value1", Key2 = "value2", Key3 = "value3" });

Woah! We went from five lines of code with dictionaries to two lines of code with object initializers (minus the type definition), to just one line of code with anonymous types!

So what does the GetHtmlLink method look like, anyway? Download the code from the attachment. You can now use the two helpers like so:

Sample link: <%= HtmlHelpers.GetHtmlLink("My Site", new { @class = "someStyle", href = "http://www.example.org" })%>
<br />
Sample URL: <%= HtmlHelpers.GetUrl("http://www.example.org/search", new { query = "kitten's mittens", mode = "details" })%>

And it'll render this HTML:

Sample link: <a class="someStyle" href="http://www.example.org">My Site</a>
<br />
Sample URL: http://www.example.org/search?query=kitten's+mittens&mode=details

So, what do you think?

I'm obviously ignoring certain aspects of this technique such as performance. There are certainly ways to optimize the performance with some clever caching. Performance might not be an issue anyway, depending on where this code is used.

Have you come up with a novel way to use a new language feature that you'd like to share?

26 Comments

  • How does this work with other languages?

  • What about doing it the following way:

    1) Create a class with an Add method

    public class Pairs : List<KeyValuePair>
    {
    public void Add(String key, String value)
    {
    Add(new KeyValuePair(key, value));
    }
    }

    2) Create a simple GetHtmlLink method

    public static string GetHtmlLink(string text, Pairs pairs)
    {
    StringBuilder sb = new StringBuilder();
    sb.Append("");
    sb.Append(text);
    sb.Append("");

    return sb.ToString();
    }

    3) Use the GetHtmlLink method

    String url = GetHtmlLink("My Site", new Pairs { {"class", "someStyle"}, {"href", "http://www.example.org"} })

    This way, no reflection and no untyped parameter. I think you went for difficult solutions first. You don't need dictionaries or anonymous types.

  • Do you really need to limit the content through your RSS feed? Since you haven't monetized your blog, how about you display the full content in your RSS feed??

  • Low tech... use a param array? Every two params is your name/value pair.

    GetUrl(string url, params string[] query)

    just assert the length of query is even :)

  • On second thought, isn't the use of reflection going to be a big problem? I don't see what you can cache efficiently as you'll pretty much get a different type for each call. I'm beginning to like the low-tech params array better...

  • I'm also in the low tech camp. When it comes down to it, that's the easiest way to use it if not the most elegant way.

    But Eilon hits on a sore note about there not really being a user friend dictionary type that's easy to construct. I run into this same situation occasionally and keep revisiting the docs for each of these collection types and walk away building something custom to make it work.

  • Jimmy, it's no coincidence! :)

    When I said "During a design meeting for a new feature in ASP.NET" I was refering to our MVC design meetings!

    - Eilon

  • I think you've been doing too much javascript and it's warped your mind.
    But I like it :-)

  • This is one of the coolest things about the MVC, I never have to hard code urls again.. the world will be a better place.


    In the CTP, will the HtmlHelper.GetUrl and GetLink type reflection be cached for performance?

    How do .net developers usually make reflective methods like these faster?

    What does the @ in @class do?

  • I would also prefer to leave c# statically typed as it is. There are plenty of other dinamically typed langugaes if I will ever want to use them.

  • Vijay, The "@" symbol is needed on the @class property because "class" is a reserved keyword in C#... so we need a way to distinguish between the keyword and just-another-property-name.

  • Not trying to bash or anything (honestly!), but anyone that has used any of the decent JavaScript libraries around these days and has passed anonymous types to functions as a way of specifying a 'dictionary' of name/value pairs and recognized that C#'s anonymous type syntax looks amazingly like JavaScript's literal object notation would have thought to try this.

    I have been using the MochiKit JS library for the last 18 months and regularly pass anonymous objects to MochiKit's DOM element creation functions like so:

    var inputElement = INPUT({type:"text", id:"foo", name:"foo"});

    setStyle(inputElement, {"background-color": "red", opacity: 0.5});

    Perhaps that is what inspired this idea? Personally, I think this is a great idea and will be looking for more ways to make my C# authoring experience feel more like my JavaScript authoring experience, which I absolutely enjoy.

  • I have to agree with Mark Brackett and dpirs. I understand that dynamic languages are all the rage right now, but C# is NOT a dynamic language, and .NET is not a dynamic framework. I use C# in .NET specifically because I WANT a statically typed language; if I wanted to use a dynamically typed language, I would use one of the many that are available. Please don't try to force dynamic constructs where they don't belong. See more discussion at http://commongenius.com/articles/archive/2006/12/07/Collection-Initializers-and-Duck-Typing.aspx.

  • By the way, since when do collections have to have an Add method with a single argument in order to use collection initializers? I haven't seen that requirement anywhere in any of the descriptions I have seen, including the Scott Guthrie link you included.

  • Hi Jonathan,
    There are a couple of ways to do what you want but both are kinda ugly in their own ways.

    1. The first is to use a custom build provider. In that implementation you'll be generating C# code (or VB, or whatever) so you can generate your own types and they'll get compiled.

    2. Implement the ICustomTypeDescriptor interface on some new type of you're choosing. In the implementation of GetProperties() you can return a custom set of PropertyDescriptors that represent properties you cooked up out of the ether. Or instead of the ether, you could get them from your XML configuration :)

    However, in the next preview of the MVC framework we'll just let you pass in dictionaries with your data instead of requiring you to use anonymous types. If you check out my newest blog post on the MVC framework I readily admit that we went "a bit too far" with the syntax :)

    Thanks,
    Eilon

  • Since this post seems to be getting some fresh link love even after being posted a while back, I thought I might post a comment that I meant to post when this subject was first brought up ages ago.

    The problem with these "anonymous types as dictionaries" approaches that have been popping up is that at the end of the day anonymous types are essentially useless "above" the method in which they are defined, short of breaking out all sorts of low-perf reflection on them or even higher-perf trickery that still needs string keys to make use of the results.

    If the main issue here is with that of the syntax required to initialize dictionaries, it doesn't even take .net 3.5, let alone anonymous types to craft extremely tight syntax for creating dictionaries. Consider this piece of sample code of mine ("D" is just a utility function that gets things going):

    IDictionary d = D()
    ["Key1", "value1"]
    ["Key2", "value2"]
    ["Key3", "value3"];

    Yes, that's all it takes, and though I will admit that the use of indexers is, well, creative, it is within the guidelines in that it really is a getter and really doesn't change the state of the object on which it was called.

    The resulting dictionary also has the benefit of actually being usable without breaking out a pile of reflection.

    As for how this is implemented, stick the following words into the back of your head this weekend: "builder", "method chaining", "immutable stack", and "implicit cast". :)

    Heck, if you think the implicit cast at the end is pushing it, you can even use an explicit one or an outright method call and the overall syntax doesn't suffer much.

    Have at it!

  • I think a lot of people are missing the point. MVC team was clearly inspired by RoR and in this case by Ruby. Creating clear cut easy for a HUMAN to read and write code is a good thing. Few would care that it makes machine's job harder.

    In ruby:

    get_html_link("Click me", :key1 => "value1", :key2 => "value2", :key3 => "value3")

    with C# we can't get syntaxt as clear, but anonymous types let us get pretty close

    GetHtmlLink("Click me", new { Key1 = "value1", Key2 = "value2", Key3 = "value3" });

    It's pretty obvious that they convert it to a basic dictionary, so what? The framework is trying to make your, developers' jobs more comfortable. I don't see anything wrong with that, even at a slight cost of an overhead.

    Web sites are very easily scaled horizontally. If having 22 boxes instead of 20 will keep your developer happier and allow you to have full suite of unit tests, who could argue with that?

  • @Alex:

    I think you are missing the point. C# is a statically typed language. I use C# because for the development that I am doing, I prefer static typing. Ruby is great when I want a dynamic language, but often I DON'T want a dynamic language. But when the major frameworks that are used by my chosen statically typed language start offering API's that only operate in a dynamically typed manner, I am forced to either use dynamic typing (or the C# equivalent), which negates the purpose of me choosing a statically typed language in the first place, or not use the framework, which negates a major reason why I chose .NET in the first place (the framework support).

    People in charge of designing these major frameworks (including the MVC team as well as the C# language team) need to get OFF the bandwagon and realize that just because dynamic languages are all the rage right now does not mean that forcing dynamic features into a statically typed language is a good idea.

  • I always liked the idea of extending the var params style of C# to also use dictionaries, so the method signature would look like:
    static void MyMethod(int argument1, params IDictionary argument2)
    And then you could call it like:
    MyMethod(10, fish = 10, food = 20);
    This comes very close, cheers.

  • Why in the world would you use an array when you can have a strongly typed list of object?

  • All these arguments are moot really, about the value of anonymous types, etc.

    You should NEVER build a web application that has its markup tags and attributes generated via dependencies in backend code like this. The whole point of CSS/XHTML and the whole Web Standards movement is to get away from the whole concept of generating HTML in the backend and separation of business logic from the UI layer. This reminds me of the messy html used in ASP.NET 1.1. The HTML Helpers are also breaking this separation in that model.

    What you should do is have a static web page with anchor tags and a full set of attributes with default values assigned. This allows UI designers control over the interface design. When it comes time to manipulate the attributes of these tags, the backend should pass in the control and change attributes as properties on that control like ASP.NET does now with HTML Server Controls, not dynamically generate these links in the backend.

    What happens if the UI designer does NOT want that anchor displayed, or wants to customize it via JavaScript, or expects to pull in additional attributes or databinding to those attributes? This model would have to be retooled. I say, all of you need to go back to school and relearn basic HTML 101.

  • How do you parse out the object to get the values?

    ie.
    new{ height=10, width=20}

    TextBox takes an object htmlAttributes
    I dont know how to take some object like this and pull the values out to pass it to the TextBox object.

  • Steve -

    You can use RouteValueDictionary's constructor to automatically "parse out" the properties and their values. If you want to see exactly how it's done just use Reflector on it and rip off the source code :)

    Thanks,
    Eilon

  • Thank you for providing this very useful article on Anonymous Types as Dictionaries.
    Best,
    Joe

  • Yeah, It would be better if C# will allow us to write code like we do in JavaScript.
    I found JavaScript more powerful. Less Code more task.
    The invention of JSON by Crockford is really marvelous. We should do something in C# like JSON.

  • I found that reflection is another way to obtain one or all values inside an anonymous type passed as parameter.
    You declare a method parameter as object and then access a property using reflection. You might consider creating a Helper class that wraps the process of obtaining the list of members (properties) or their values.

Comments have been disabled for this content.