Search code examples
c#reflectiongenericsidictionary

Getting values of a generic IDictionary using reflection


I have an instance that implements IDictionary<T, K>, I don't know T and K at compiletime, and want to get all elements from it. I don't want to use IEnumerable for some reason, which would be the only non-generic interface implemented by IDictionary.

Code I have so far:

// getting types
Type iDictType = instance.GetType().GetInterface("IDictionary`2");
Type keyType = iDictType.GetGenericArguments()[0];
Type valueType = iDictType.GetGenericArguments()[1];

// getting the keys
IEnumerable keys = (IEnumerable)dictType.GetProperty("Keys")
  .GetValue(instance, null);

foreach (object key in keys)
{
  // ==> this does not work: calling the [] operator
  object value = dictType.GetProperty("Item")
    .GetValue(instance, new object[] {key } );


  // getting the value from another instance with TryGet
  MethodInfo tryGetValue = iDictType.GetMethod("TryGetValue");
  object[] arguments = new object[] { key, null };
  bool hasElement = (bool)tryGetValue.Invoke(otherInstance, arguments);
  object anotherValue = arguments[1];
}

I could also call TryGetValue, but I think it should be possible to call the [] operator. Can anybody help me?


Solution

  • It would be better to figure out the TKey / TValue, and switch into regular code via MakeGenericMethod - like so:

    (edit - you could pass in the otherInstance as an argument too, if they are of the same type)

    static class Program
    {
        static void Main()
        {
            object obj = new Dictionary<int, string> {
                { 123, "abc" }, { 456, "def" } };
    
            foreach (Type iType in obj.GetType().GetInterfaces())
            {
                if (iType.IsGenericType && iType.GetGenericTypeDefinition()
                    == typeof(IDictionary<,>))
                {
                    typeof(Program).GetMethod("ShowContents")
                        .MakeGenericMethod(iType.GetGenericArguments())
                        .Invoke(null, new object[] { obj });
                    break;
                }
            }
        }
        public static void ShowContents<TKey, TValue>(
            IDictionary<TKey, TValue> data)
        {
            foreach (var pair in data)
            {
                Console.WriteLine(pair.Key + " = " + pair.Value);
            }
        }    
    }