Custom Collection Initializers

You might already know that .NET 3.5 supports inline collection initialization like this:

var romanNumerals = new Dictionary<int, string>
{
    { 1000, "M" },
    { 900, "CM" },
    { 500, "D" },
    { 400, "CD" },
    { 100, "C" },
    { 90, "XC" },
    { 50, "L" },
    { 40, "XL" },
    { 10, "X" },
    { 9, "IX" },
    { 5, "V" },
    { 4, "IV" },
    { 1, "I" }
};

This is described nicely by Mads Torgersen here.  You can initialize custom collections in the same way; all you need to do is provide an ‘Add’ method (see Mads’ post if you’re curious why they don’t just rely on ICollection<T>).  Here’s an example of how it could be used:

public static class NumberConversion
{
    private class KeyValueList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
    {
        public void Add( TKey key, TValue value )
        {
            Add( new KeyValuePair<TKey, TValue>( key, value ) );
        }
    }

    private static KeyValueList<int, string> numerals = new KeyValueList<int, string>
    {
        { 1000, "M" },
        { 900, "CM" },
        { 500, "D" },
        { 400, "CD" },
        { 100, "C" },
        { 90, "XC" },
        { 50, "L" },
        { 40, "XL" },
        { 10, "X" },
        { 9, "IX" },
        { 5, "V" },
        { 4, "IV" },
        { 1, "I" }
    };

    public static string ToRoman( this int number )
    {
        var roman = new StringBuilder();

        foreach ( var numeral in numerals )
        {
            while ( number >= numeral.Key )
            {
                roman.Append( numeral.Value );
                number -= numeral.Key;
            }
        }

        return roman.ToString();
    }
}

This could be extended to include any number of parameters (not just key / value pairs).  Additionally, the initialization rows don’t all need to hit the same ‘Add’ method; you can use as many overloads as you like 🙂

Leave a comment