Reputation: 7304
I think this is the first time I'm using the new C#6 dictionary-initialization feature, and I need a nested structure like the below one:
var map = new Dictionary<string, Dictionary<string, object>>()
{
["WNodeScramblingResetZone_Unlock"] =
{
["updater"] ="pinco",
["rdlev"] = 55
},
["WNodeScramblingResetZone_NewPwd"] =
{
["updater"] ="pallo",
["wrlev"] = 75,
["is_online"] = true
}
};
This syntax seems fine: no compilation errors. However, when the program starts I see a couple of "KeyNotFoundException" errors in the output window, and the application does not work.
By the way, if I explicitly declare the nested type instantiation, everything runs fine.
var map = new Dictionary<string, Dictionary<string, object>>()
{
["WNodeScramblingResetZone_Unlock"] = new Dictionary<string, object>()
{
["updater"] ="pinco",
["rdlev"] = 55
},
["WNodeScramblingResetZone_NewPwd"] = new Dictionary<string, object>()
{
["updater"] ="pallo",
["wrlev"] = 75,
["is_online"] = true
}
};
Is that a limitation, a bug, or rather there is a concrete reason to define it?
Upvotes: 4
Views: 192
Reputation: 4280
I used http://tryroslyn.azurewebsites.net/ to translate this C# code into VB.NET:
Public Class Program
Public Shared Sub Main()
Dim expr_06 As Dictionary(Of String, Dictionary(Of String, Object)) = New Dictionary(Of String, Dictionary(Of String, Object))()
expr_06("x")("updater") = "pinco"
expr_06("x")("rdlev") = 55
expr_06("y")("updater") = "pallo"
expr_06("y")("wrlev") = 75
expr_06("y")("is_online") = True
End Sub
End Class
It cleary shows that new dictionaries are not created only accessed by key. The new [key] = value
syntax compiles to dictionary[key] = value
not like old one {key, value}
which compiled to dictionary.Add(key, value)
.
I think this is a feature, compiler doesn't know what type of IDictionary
you need so you must provide concrete type. There is also posibility that you use some dynamic collection that automatically creates subdictionnaries on first access in that case this code would work. As you may see compiler leaves you great freedom to do what you want at the expense of program verbosity.
EDIT: I write a bit lengthy blog post about initializers that provides a more deep explanation
Upvotes: 1
Reputation: 244797
When you write code like this:
var map = new Dictionary<string, Dictionary<string, object>>()
{
["WNodeScramblingResetZone_Unlock"] =
{
["updater"] ="pinco"
}
};
It's compiled into the equivalent of this:
var map = new Dictionary<string, Dictionary<string, object>>()
map["WNodeScramblingResetZone_Unlock"]["updater"] = "pinco";
It does not create any instances that you didn't explicitly specify.
This is code that could work (which is why it's allowed) for some dictionary-like class, which returns empty collection for keys that don't exist, but will indeed cause KeyNotFoundException
for Dictionary
.
On the other hand, this code:
var map = new Dictionary<string, Dictionary<string, object>>()
{
["WNodeScramblingResetZone_Unlock"] = new Dictionary<string, object>()
{
["updater"] ="pinco"
}
};
Is compiled as:
var map = new Dictionary<string, Dictionary<string, object>>();
var tmp = new Dictionary<string, object>();
tmp["updater"] = "pinco";
map["WNodeScramblingResetZone_Unlock"] = tmp;
As you can see, this calls the map["WNodeScramblingResetZone_Unlock"]
setter with a new instance (instead of the getter in the previous version), which is why it works.
Upvotes: 3