Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IDictionary assignment shortcuts compiler feature or language feature?

Through some random object creation today I came across this neat little shortcut for a Dictionary<K, V>. Is the following assignment a compiler shortcut or is it a feature of Dictionary<string, string>.

IDictionary<string, string> items = { { "item1key", "item1value" } };

Looking at the source for Dictionary<K, V> I don't see anything offhand for how this works. Implementing all the interfaces for this class dot not allow me to perform a similar operation. Why is it that we can do it for a dictionary but not another type. For example, how does the compiler or language feature know that the first item is a key and the second item is the value. Or even more specific this same syntax can't be used for a List<string>

List<string> items = { "item1" };

So the first is valid, why?

I'm not necessarily trying to duplicate this but rather curious as to why it is the way it is. What makes a dictionary special in this case?

Example that works

public class Button
{
    public string Title { get; set; }
    public ButtonType Type { get; set; }
    public IDictionary<string, string> Items { get; set; }
    public bool RequiresSelected { get; set; }
}

var buttons = new List<Button>
    {
        new Button { 
            Items = {
                        {"button1", "Button 1"},
                        {"button2", "Button 2"},
                        {"button3", "Button 3"},
                    }, 
            Title = "3 Buttons", 
            Type = ButtonType.DropDown 
        }
    };
like image 644
Buildstarted Avatar asked Jan 17 '23 19:01

Buildstarted


1 Answers

The syntax you've shown isn't valid in C#. You'd need:

IDictionary<string, string> items = new Dictionary<string, string>
    { { "item1key", "item1value" } };

At that point it's just a normal collection initializer, so the list equivalent would be:

List<string> items = new List<string> { "item1" };

EDIT: Let's see if my edit can beat yours. My guess is that you've seen something like:

var foo = new Foo {
    SomeDictionaryProperty = { 
         { "item1key", "item1value" }
    }
};

That's an embedded collection initializer, and can be used for lists too. It's not creating a new dictionary, it's adding to an existing one. The code above is equivalent to:

var tmp = new Foo();
tmp.SomeDictionaryProperty.Add("item1key", "item1value");
var foo = tmp;

Another example of it working:

var form = new Form {
    Controls = { new Label { Text = "Foo"}, new Label { Text = "Bar" } }
};

See section 7.6.10.2 of the C# 4 specification (Object Initializers) for more information. The important bit is this:

member-initializer:
    identifier   =   initializer-value

initializer-value:
    expression
    object-or-collection-initializer

So you can initialize a property to either be a specific value (in which case the setter will be used) or via an object/collection initializer, in which case the getter for the property will be used, and then setters or the Add method will be used for the body of the object/collection initializer.

like image 129
Jon Skeet Avatar answered Jan 20 '23 17:01

Jon Skeet