Are the keys in a Dictionary<TKey, TValue> immutable? - c#

I get a Dictionary<string, string> back from an API but depending on certain rules need to modify some of the key names.
Before I head down the road of copying to a new Dictionary I just wanted to confirm that the keys in a Dictionary<TKey, TValue> are immutable.

You are right, if the key changes, you will need to remove the entry with the old key and insert a new entry with the new key.
If only some of the keys change, you don't need to copy the entire dictionary. Both Add and Remove operations on Dictionary are roughly O(1) operations.

It is more like that you have to make sure that the type you use for TKey is immutable if it is a reference type. String is immutable, by the way. Value types can be mutable, but you don't get the opportunity to modify the stored key in the Dictionary.

The keys in a Dictionary<string, string> are immutable.
For instance, the following code:
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("One", "1");
dict.Add("Two", "2");
var k = dict.First();
k.Key = "Three";
Will throw the following compiler error:
Property or indexer
'System.Collections.Generic.KeyValuePair.Key'
cannot be assigned to -- it is read
only
That being said, a Dictionary<T, T> may have mutable keys if you use a reference type, see:
C# Dictionary<> and mutable keys
(I know, I know, strings are reference types... but the link above will explain...)

Related

How to add values to a list inside a dictionary of objects?

I have a dictionary of objects. Then I created an empty List as an element of that dictionary.
Dictionary<string, object> mydictionary = new Dictionary<string, object>();
mydictionary["names"] = new List<string>();
Then I try to add a name into the List, but couldn't.
mydictionary["names"].Add("Jack"); -> ERROR "object does not contain definition of Add"
How can I add values to this List?
Note: I can't change the dictionary type. It must be <string,object>.
The compiler only knows that the entries are of type object, at compile time it doesnt know that this object is one that supports Add. I mean what Add would that be? You could also have a BigInteger object and a database. SO the compiler doesnt know how to do
mydictionary["name"].Add()
because it doesn't know what Add to call, or even if the object has an Add. This is because c# is a statically typed language. You need to tell the compiler what the object is
((List<string>)mydictionary["name"]).Add()
ie cast the object to the right type.
You have to specifically mention the type of value, like
((IList<string>) mydictionary["names"]).Add("Jack");
or you can use as
(mydictionary["names"] as (IList<string>)).Add("Jack");
Why?
Because you declared dictionary as a <string, object>.
When you added key-value pair i.e. mydictionary["names"] = new List<string>();, the value get stored as an object not a List.
This is the reason when you are trying to add any string to a list, dictionary value is not recognized as a list,
We fixed this problem, by type-casting an object to a list.

Can anyone give an example of a generic type for dynamically growing chained hashtables?

What's the best way to implement a chained hashtable in C#? For example, the class would be declared like this:
DynamicHashtable<Tkey, Tvalue>
{
....methods
}
Where Tkey is the type of the key stored in the table, and TValue is the type of the values associated with the keys. Thus, a hashtable whose keys are strings and whose associated values are integers would be
DynamicHashtable<string, int>
You can use Hashtable class.
If you wish to see details of implementation Hashtable you can review Source Code here.

How to destroy C# data like Dictionary<string, List<Action<object>>>?

I defined an object like Dictionary<string, List<Action<object>>> to store some delegate methods to invoke. If I wanna destroy this Dictionary. Should I need to call List.Clear() first in Dictionary? Or just call Dictionary.Clear will be ok?
This one:
foreach(KeyValuePair<string, List<Action<object>>> kvp in dict)
{
kvp.Value.Clear();
}
dict.Clear();
dict = null;
Or this one:
dict.Clear();
dict = null;
If you are about to drop the last live reference to dict, don't bother with any of it: simply assign null if dict remains in scope, or don't do anything if the scope of dict is about to end.
Explicit clearing of the dictionary or any of the lists that it contains is not required, because garbage collector would take care of it either way. Explicit clearing of the dictionary and the lists it contains would be a waste of CPU cycles.
As long as you don't have a reference on the objects stored in the Dictionary or the Dictionary itself, you can just set it to null.
dict = null;
GC will take care of the rest.
this alone will do. Clearing the reference of the dictionary is needed only if it is declared at global level. Local objects are not needed to be cleared.
dict = null;
As long as reference of the object is cleared it will be cleared from memory on next GC of that generation.

Are elements in a .NET's Dictionary sequential? [duplicate]

This question already has answers here:
The order of elements in Dictionary
(6 answers)
Closed 9 years ago.
Say, if I create a dictionary like this:
Dictionary<string, MyClass> dic = new Dictionary<string, MyClass>();
dic.add("z1", val1);
dic.add("abc9", val2);
dic.add("abc8", val3);
dic.add("ABC1", val4);
So when I do:
foreach (KeyValuePair<string, MyClass> kvp in dic)
{
}
Am I guaranteed to have these values retrieved as such: "z1", "abc9", "abc8", "ABC1"?
And what if I first do this, will it be: "z1", "abc8", "ABC1"?
dic.Remove("abc9");
No. From MSDN (emphasis mine)
For purposes of enumeration, each item in the dictionary is treated as
a KeyValuePair<TKey, TValue> structure representing a value and its
key. The order in which the items are returned is undefined.
You may want to look at the OrderedDictionary class if you want more control over the iteration order.
The short answer is No. Order is not guaranteed in a Dictionary<TKey, TValue>, nor should you count on order being maintained.
You might want to check into OrderedDictionary instead.
Example:
OrderedDictionary d = new OrderedDictionary();
d.Add("01", "First");
d.Add("02", "Second");
d.Add("03", "Third");
d.Add("04", "Fourth");
d.Add("05", "Fifth");
for(int i = 0; i < d.Count; i++) // Print values in order
{
Console.WriteLine(d[i]);
}
Note there's no generic OrderedDictionary<TKey,TValue> version for some odd reason. However, this question has some hints on how to implement one.
Am I guaranteed to have these values retrieved as such: "z1", "abc9", "abc8", "ABC1"?
Absolutely not. Always treat Dictionary<,> as an unordered collection of key/value pairs. Even though as an implementation detail you'll generally see them in insertion order if you only ever add values, you should not rely on this.
From the documentation:
For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<TKey, TValue> structure representing a value and its key. The order in which the items are returned is undefined.
(Emphasis mine.)
If you need a particular order, you should use a different collection - potentially in conjunction with a dictionary, if you also need to be able to fetch by key. (It's not entirely uncommon to maintain an IList<TKey> as well as a Dictionary<TKey, TValue> for example.)
No, there is no guarantee of elements order. Also, it can be different depending on actual implementation of IDictionary<...> interface.

Dynamically loading Dictionary KVPs into Anonymous types

I want to load all the KeyValuePairs in a Dictionary<string, string> into anonymous types during runtime. There will be no knowledge ahead of time of the contents of the Dictionary.
Dictionary<string, string> callParams = new Dictionary<string, string>();
logger.WithParams(() => new { Val1= val1, Val2= val2, Val3= val3 });
How can I add the KVPs of callParams to the set of anonymous types?
It's not really clear what you mean - but if you're trying to get the property names to depend on the keys in the dictionary, you're out of luck: anonymous types are created for you by the compiler at compile-time, with the property names that you specify. If you don't know the keys until execution time, you can't have the anonymous types...
If you're using .NET 4 you could potentially use ExpandoObject and dynamic typing... but what's the bigger picture here? Why can't you just pass the dictionary around as it is?

Categories

Resources