Is it possible to cast a Dictionary
to a consistent intermediate generic type? So I would be able to cast
Even if you could find some way to express this, it would be the wrong thing to do - it's not true that a Dictionary<string, bool>
is a Dictionary<string, object>
, so we definitely don't want to cast. Consider that if we could cast, we could try and put a string
in as a value, which obviously doesn't fit!
What we can do, however, is cast to the non-generic IDictionary
(which all Dictionary<,>
s implement), then use that to construct a new Dictionary<string, object>
with the same values:
FieldInfo field = this.GetType().GetField(fieldName);
IDictionary dictionary = (IDictionary)field.GetValue(this);
Dictionary<string, object> newDictionary =
dictionary
.Cast<dynamic>()
.ToDictionary(entry => (string)entry.Key,
entry => entry.Value);
(note that you can't use .Cast<DictionaryEntry>
here for the reasons discussed here. If you're pre-C# 4, and so don't have dynamic
, you'll have to do the enumeration manually, as Gibsnag's answer does)
Following AakashM's answer, the Cast doesn't seem to play ball. You can get around it by using a little helper method though:
IDictionary dictionary = (IDictionary)field.GetValue(this);
Dictionary<string, object> newDictionary = CastDict(dictionary)
.ToDictionary(entry => (string)entry.Key,
entry => entry.Value);
private IEnumerable<DictionaryEntry> CastDict(IDictionary dictionary)
{
foreach (DictionaryEntry entry in dictionary)
{
yield return entry;
}
}
The duck typing in foreach is handy in this instance.
Yes It is possible to cast the FieldInfo
to Dictionary
as below
This is one example, I have used in my code
Dictionary<string, string>
GetTheDict = FilesAndPaths.GetType()
.GetFields()
.Where(f => f.Name.Equals(pLoadFile))
.Select(f => (Dictionary<string, string>)f.GetValue(FilesAndPaths))
.Single();
When I stumbled onto the same situation, I created the following helper:
/// <summary>
/// Casts a dictionary object to the desired Dictionary type.
/// </summary>
/// <typeparam name="TKey">The target Key type.</typeparam>
/// <typeparam name="TValue">The target value type.</typeparam>
/// <param name="dictionary">The dictionary to cast.</param>
/// <returns>A copy of the input dictionary, casted to the provided types.</returns>
private Dictionary<TKey, TValue> CastDictionary<TKey, TValue>(IDictionary dictionary)
{
// Get the dictionary's type.
var dictionaryType = typeof(Dictionary<TKey, TValue>);
// If the input is not a dictionary.
if (dictionaryType.IsAssignableFrom(typeof(Dictionary<,>)))
{
// Throw an exception.
throw new Exception("The cast to a dictionary failed: The input object is not a dictionary.");
}
// Get the generic arguments of the dictionary.
var arguments = dictionaryType.GetGenericArguments();
// If the first type of the dictionary is not a descendant of TKey.
if (!(arguments[0] is TKey || arguments[0].IsAssignableFrom(typeof(TKey)))
// Or its second type is not a descendant of TValue.
|| !(arguments[1] is TValue || arguments[1].IsAssignableFrom(typeof(TValue))))
{
// Throw an exception.
throw new Exception("The cast to a dictionary failed: The input dictionary's signature does not match <" + typeof(TKey).Name + ", " + typeof(TValue).Name + ">");
}
// Get the dictionary's default constructor.
var constructor = dictionaryType.GetConstructor(Type.EmptyTypes);
// Create a new dictionary.
var output = (Dictionary<TKey, TValue>)constructor.Invoke(null);
// Loop through the dictionary's entries.
foreach (DictionaryEntry entry in dictionary)
{
// Insert the entries.
output.Add((TKey)entry.Key, (TValue)entry.Value);
}
// Return the result.
return output;
}
Could be used in your case as follows:
FieldInfo field = (IDictionary)this.GetType().GetField(fieldName);
Dictionary<string, Object> dict = CastDictionary<string, Object>(field.GetValue(this));
Consider whether casting to and from object
really is necessary. I started down that path and stumbled across this article, before realising I could achieve what I needed through generics rather than conversion. For example;
class DictionaryUtils<T>
{
public static T ValueOrDefault(IDictionary<string, T> dictionary, string key)
{
return dictionary.ContainsKey(key) ? dictionary[key] : default(T);
}
}
This bit of code is much cleaner and will be faster than the equivalent conversion code shown in other answers.
Is this helping you ?
Dictionary<a, b> output =
input.ToDictionary(item => item.Key, item => (SomeType)item.Value);