I'm trying to get the setter function of a dictionary item value. I know the object is a Dictionary< TKey,TValue>, but I don't know the types of Tkey and TValue, so I think my only resort is to use an IDictionary.
In pseudo code, I want to do something like this;
Action<object> keySetter = dictionary.items[index].value.setter
Action<object> valueSetter = dictionary.items[index].key.setter
Unfortunately the IDictionary has no indexer and I'm not sure how to get to the actual keys and values.
Right now I'm looping through the dictionary entries and get the setter from that, but whenever I call the setter it doesn't seem to change to value in the dictionary. So I suspect the DictionaryEntry is a copy and doesn't point to the actual value in the dictionary.
//for simplicity sake a Dictionary is added here, but usually the TKey and Tvalue are not known
IDictionary target = new Dictionary<int, string>();
target.Add( 0, "item 1" );
foreach ( DictionaryEntry dictionaryEntry in target )
{
//want to get the setter for the item's key setter and value setter
PropertyInfo keyProperty = dictionaryEntry.GetType().GetProperty( "Key" );
PropertyInfo valueProperty = dictionaryEntry.GetType().GetProperty( "Value" );
Action<object> keySetter = ( val ) =>
{
keyProperty.SetMethod.Invoke( dictionaryEntry, new object[] { val } );
};
Action<object> valueSetter = ( val ) =>
{
valueProperty.SetMethod.Invoke( dictionaryEntry, new object[] { val } );
};
keySetter.Invoke( 1 );
valueSetter.Invoke( "item 1 value succesfully modified" );
Console.WriteLine( target.Keys ); //no change
Console.WriteLine( target.Values ); //no change
}
Since I do know that the IDictionary is actually a Dictionary< TKey, TValue> underneath, maybe I can do some reflection magic to get the setter that way?
When you enumerate entries of a Dictionary, Key and Value are copied from Dictionary's internal structures (Entry[]) to new instances of KeyValuePair or DictionaryEntry. Therefore trying to modify these DictionaryEntry is futile, because these changes are not propagated back to the dictionary. To modify Dictionary, you have to use it's indexer or Add, Remove or similar methods.
C# indexers are just a syntactic sugar to use the Dictionary<TKey,TValue>.Item property. So when using reflection, you have to use this property instead.
To create value setter for each item in a Dictionary, you need to get a key for each of these items and then use it as an index argument when setting new value to the Dictionary using it's Item property. Creating a key setter is more difficult, because Dictionary doesn't support changing of existing key. What you have to do is actually remove existing item from the Dictionary and insert a new one with the new key:
// Dictionary.Item property we will use to get/set values
var itemProp = target.GetType().GetProperty("Item");
// Since you want to modify dictionary while enumerating it's items (which is not allowed),
// you have to use .Cast<object>().ToList() to temporarily store all items in the list
foreach (var item in (target as IEnumerable).Cast<object>().ToList())
{
// item is of type KeyValuePair<TKey,TValue> and has Key and Value properties.
// Use reflection to read content from the Key property
var itemKey = item.GetType().GetProperty("Key").GetValue(item);
Action<Object> valueSetter = (val) => itemProp.SetValue(target, val, new object[] { itemKey });
// valueSetter(someNewValue);
// It's not possible to just change the key of some item. As a workaround,
// you have to remove original item from the dictionary and insert a new item
// with the original value and with a new key.
Action<Object> keySetter = (key) =>
{
// read value from the dictionary for original key
var val = itemProp.GetValue(target, new object[] { itemKey });
// set this value to the disctionary with the new key
itemProp.SetValue(target, val, new object[] { key });
// remove original key from the Dictionary
target.GetType().GetMethod("Remove").Invoke(target, new Object[] { itemKey });
// need to "remember" the new key to allow the keySetter to be called repeatedly
itemKey = key;
};
// keySetter(someNewKey);
}
Related
I have the method
HandleNotification(string message, Dictionary<string, object> additionalData, bool isActive)
and I would take the from additionalData the value.
I have this additional data:
Extracoins:4
I don't understand how I can take the value 4 from additionalData for a specific key Extracoins.
You can get a value from a Dictionary like this if your only interested in accessing one specific key.
object value = null;
additionalData.TryGetValue("Extracoins", out value);
That way object will be the value in the Dictionary or it will remain null if the value is not found.
Or you can do:
if (additionalData.ContainsKey("Extracoins"))
{
object value = additionalData["Extracoins"];
}
Finally if you wanted to iterate over all the values in the Dictionary until you get the correct value you could do:
object value = null;
foreach (KeyValuePair<string, object> pair in additionalData)
{
if (pair.Key == "Extracoins")
{
value = pair.Value;
}
}
In my desktop C# application I start with a dictionary. I want to be able to check this dictionary for a key. If the dictionary has this key, I would like to pass it on to a method. If the dictionary doesn't have this key, I would like to create a blank list and just pass that on instead. How can I do this?
I get the error "given key was not present in the dictionary". Can I add a default so it is never null maybe?
// myDic was declared as a Dictionary<string, List<string>
// Here is how I call someFunction
string text = SomeFunction(stringValue1, stringValue2, myDic[field1.field2]);
// SomeFunction looks like this
string SomeFunction (string string1, string string2, List<string> ra)
{
// method
return stringResult;
}
Updated based on comments. To pass one key that may or may not exist you may do this(assuming the value is a List):
// assuming the method we are calling is defined like this:
// public String SomeFunction(string string1, String string2, List<String> ra)
List<string> valueToPassOn;
if (_ra.ContainsKey(lc.Lc))
{
valueToPassOn = _ra[lc.Lc]
}
else
{
valueToPassOn = new List<string>();
}
string text = tooltip.SomeFunction(something1, something2, valueToPassOn);
Should you want to pass an entire dictionary (as the question originally read), regardless of whether or not the dictionary exists:
You have two options. Either create the dictionary regardless like this:
if (myDic == null)
{
// change var and var2 to the types of variable they should be, ex:
myDic = new Dictionary<string, List<string>>();
}
string text = SomeFunction(stringValue1, stringValue2, myDic);
or, what is probably the better option, in the declaration of the function SomeFunction add a dictionary as a variable with a default parameter. Just be sure that your function knows what to do if the dictionary is null.
string SomeFunction(string string1, string string2, Dictionary dictionary = null)
{
// method here
}
You can check if the key exists using ContainsKey method and if it returns false you can pass a default value you want:
// replace default(string) with the value you want to pass
// if the key doesn't exist
var value = myDic.ContainsKey(field1.field2) ? myDic[field1.field2] : default(string);
string text = SomeFunction(stringValue1, stringValue2, value);
What you need to do is make sure the dictionary actually contains the given key in the dictionary.
If you need to extract the value by key, use TryGetValue method:
string value;
if (myDict.TryGetValue(key, out value))
{
// Key exists in the dictionary, do something with value.
}
Use one of the following snippets in order to check if dictionary is empty and take some action:
var x = new Dictionary<string, string>();
if (x.Any())
{
//....
}
if (x.ContainsKey("my key"))
{
}
if (x.ContainsValue("my value"))
{
}
if (x.Count > 0)
{
}
I have a function that gets two strings - a key and a value.
I need to parse the value from string to enum.
the key represent which enum I need to use.
I wanted to use "if"s -
if (keyString == "e1")
{
(MyEnum1)Enum.Parse(typeof(MyEnum1), valueString, true);
}
else if (keyString == "e2")
{
(MyEnum2)Enum.Parse(typeof(MyEnum2), valueString, true);
}
else if .....
But then I thought maybe I can create a dictionary of key and enum -
<"e1", MyEnum1>,
<"e2", MyEnum2>,
...
and then use the dictionary's values for the enum parsing
(dic[keyString])Enum.Parse(typeof(dic[keyString]), valueString, true)
but I couldn't do it..
I there any other way?
Just store the type directly in the dictionary (i.e. store the result of typeof(MyEnum1)):
Dictionary<string, Type> KeyToEnum = new Dictionary<string, Type>();
KeyToEnum["e1"] = typeof(MyEnum1);
KeyToEnum["e2"] = typeof(MyEnum2);
Object EnumValue = Enum.Parse(dic[keyString), valueString, true);
// Note that EnumValue is an object, because we can't know at compile time what the type will be.
Note that if instead of "e1", "e2"... you actually had "MyEnum1", "MyEnum2" (i.e. the actual name of the type you could do Type.GetType(MyKey) instead of the dictionary.
I'm looking way to Create KeyValuePair instance and setting key & Value dynamically using reflection.
This is part of
foreach(var prop in this.GetType().GetProperties())
loop which iterates through properties and tries to recover them according to some conditions. KeyValue Pair is seems to be complicated.
I have these two type definitions
var keyType = prop.PropertyType.GetGenericArguments()[0];
var valueType = prop.PropertyType.GetGenericArguments()[1];
Here I can create an Instance of my KeyValuePair..
var keyValuePair = Activator.CreateInstance(prop.PropertyType);
But the key and the value are read only properties from outside and could be set only by constructor.
Any Ideas ??
Call the constructor with the values for Key and Value:
var keyValuePair = Activator.CreateInstance(prop.PropertyType, new [] {key, val});
Dictionary dict;
what's the diff between
dict.add(key, value) and dict[key] = value
dict[key] = value will add the value if the key doesn't exist, otherwise it will overwrite the value with that (existing) key.
Example:
var dict = new Dictionary<int, string>();
dict.Add(42, "foo");
Console.WriteLine(dict[42]);
dict[42] = "bar"; // overwrite
Console.WriteLine(dict[42]);
dict[1] = "hello"; // new
Console.WriteLine(dict[1]);
dict.Add(42, "testing123"); // exception, already exists!
As Ahmad noted, dictionary[key] = value; will add the value if the key doesn't exist, or overwrite if it does.
On the other hand, dictionary.Add(key, value); will throw an exception if key exists.
The Add operation will fail (throws ArgumentException) if the key already exists in the dictionary. The [] operation will either add the key if it doesn't exist or update it if the key does exist.