Reputation: 21
I am attempting to use System.Reflection to modify values in a generic dictionary in which I do not know the types of the IKey and IValue. I am able to set the values of the Dictionary.Entry.value for each entry in the dictionary using a series of GetField(), GetValue(), and SetValue() statements (code below), but the values returned by dict[key] still return the unaltered values.
Here is simple example of what I want to do (real code is after this):
dict["some key"] = "some value";
// Use reflection to do a SetValue dict.entries[0] to "some new value"
Printing out dict["some key"] should now display "some new value"
Instead, it prints out the original value. In the code below you'll see that the key is a match, and a GetValue() call after the SetValue() retrieves the new value. I'm at a loss as to why this is happening.
Here is the code:
const BindingFlags BINDING_FLAGS_ALL = (BindingFlags) 65535;
Dictionary<string, string> dict = new Dictionary<string, string>();
dict["key1"] = "original value";
object entry = ((Array) dict.GetType().GetField("entries", BINDING_FLAGS_ALL).GetValue(dict)).GetValue(0);
object key = entry.GetType().GetField("key", BINDING_FLAGS_ALL).GetValue(entry);
FieldInfo val_field = entry.GetType().GetField("value", BINDING_FLAGS_ALL);
object val = val_field.GetValue(entry);
Console.WriteLine($"original value at '{key}' == '{val}'");
val_field.SetValue(entry, "changed value!");
val = val_field.GetValue(entry);
Console.WriteLine($"new value at '{key}' == '{val}'");
val = dict[(string) key];
Console.WriteLine($"dict[{key}] == '{val}'");
The output is:
original value at 'key1' == 'original value'
new value at 'key1' == 'changed value!'
dict[key1] == 'original value'
Thanks in advance for the guidance! dd
Upvotes: 0
Views: 110
Reputation: 740
Update
As pointed out in the comments, you can cast the dictionary to a non-generic IDictionary
first:
var dict = new Dictionary<string, string>();
((IDictionary)dict)["key1"] = "changed value!";
// Works
((IDictionary)dict)[10] = 50;
// Also works, just generates
// an exception because the dictionary is of type string
// (but at least compiles and runs)
Original answer
Each type that has an indexer also includes hidden methods: get_Item
and set_Item
.
My approach is to invoke the set_Item
method with reflection:
Dictionary<string, string> dict = new Dictionary<string, string>();
dict["key1"] = "original value";
var type = dict.GetType();
var setItemMethod = type.GetMethod("set_Item");
setItemMethod.Invoke(dict, new object[] { "key1", "changed value!" });
Console.WriteLine(dict["key1"]);
This program will display the output changed value!
.
It works even for dictionaries that you don't know the type of, simply change parameters of the Invoke
method to any type:
setItemMethod.Invoke(dict, new object[] { 10, 50 }); // for integers
Upvotes: 2
Reputation: 4855
Entry
is a struct.
So you are working with a copy of it, not the one that Dictionary internally uses.
Upvotes: 1