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);