How to get Dictionary<Tkey, TValue> entry information through reflection?

I have been working on some code that probe through the entries of a generic dictionary Dictionary<TKey, TValue>, using reflection. Unlike working with Hashtable, it's not easy to find out the entries' key and value information. Here is the code depict the problem.

Suppose I have a class hold two fields:

public class MyClass

{

Dictionary<string, DateTime> m_dateTimeDictionary;

Hashtable m_dateTimeHashTable;

}

I have an instance of the class and its type info:

MyClass myClass = new MyClass();

Type myType = myClass.GetType();

I have some code that probe through the reflection:

foreach (FieldInfo fi in myType.GetFields(BindingFlags.Public |

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))

{

Type IEnumerableType = fi.FieldType.GetInterface("IEnumerable",

true);

if (IEnumerableType != null)

{

IEnumerable iEnum = (IEnumerable)fi.GetValue(myClass);

foreach (object de in iEnum)

{

}

}

}

I am interested to find out the information of variable de. For the Hashtable field m_dateTimeHashTable I can cast de to DictionaryEntry, then from DictionaryEntry I can get the key and value object. For the Dictionary field m_dateTimeDictionary the only type that I can cast de to is KeyValuePair<string, DateTime>. From the KeyValuePair I also have not problem to access the key and value. But the problem is during coding time I don't suppose to know the precise type of the entries. So, my question is without knowing the dictionary type, how to get the key and value object of each entry I thought about implement my probing code using generic. But it won't help if the client class that I am trying probe with has multiple fields of multiple dictionary types.

Anybody have don't this before Thanks!



Answer this question

How to get Dictionary<Tkey, TValue> entry information through reflection?

  • ArunBandy

    I need the IEnumerable interface to find out all the keys and values. Without knowing anything about the dictionary I can not make much use of IDictionary.
  • ariana28

    John Cheng wrote:

    Unlike working with Hashtable, it's not easy to find out the entries' key and value information.



    I am not going to answer your question directly; but challenge an assumption which may change your design or approach.

    It is easy to access key value pairs and enumerate through a dictionary type object. Example:

    Dictionary<string,string> genList = new Dictionary<string,string>();

    genList.Add("Hello", "World");
    genList.Add("Hash", "Table");

    StringBuilder sb = new StringBuilder();

    foreach (KeyValuePair<string, string> item in genList)
    sb.AppendFormat("{0}\t{1}{2}",
    item.Value,
    item.Key,
    System.Environment.NewLine);

    Console.Write(sb.ToString()); // Outputs all string value pairs.


    Hope this helps. Good luck.


  • SWhittet

    Object o = <SomeKeyValuePairOfUnknowType>;

    Type kvpType = o.GetType(); // the actual type of the KeyValuePair.

    Type[] kvpArguments = kvpType.GetGenricArguments();

    Type tKey = kvpArguments[0];

    Type tValue = kvpArguments[1];

    To create an object of tKey, tValue.

    object CreateKeyValuePair(Type tKey, Type tValue)

    {

    Type kvpType = typeof(KeyValuePair<,>); // the unbound generic type.

    Type boundKvp = kvpType.MakeGenericType(new Type[] { tKey, tValue });

    // somebody else can explain how to construct an object from a boudn type.

    // It can be done at runtime.

    // I've seen it, just can't remember it off the top of my head.

    }


  • BALA SINGAM

    > try querying the type for the IDictionary interface instead of the IEnumerable interface

    You are on the right track, but one level above. The crux of this issue revolves around what Dictionary.Enumerator.Current returns. That return is a KeyValuePair Generic Structure . Such a return is used in the foreach:
    foreach (KeyValuePair<int, string> kvp in myDictionary) {...}
    What these forum messages are trying to accomplish is how does one, via reflection dynamically define a kevalue pair; ie how does one replace the definition section as what is shown in red above in a dynamic fashion at runtime It seems only at compile time can one do that.


  • Robert Kozak

    The whole point of using the generic collections is for strong typing. If you are using reflection to determine types at runtime then you are not using strong typing, so dont bother with the Dictionary<>; just use a hashtable.

    Your approach seems to have some funamental problems with it. Can you explain what it is that your are trying to accomplish, and why you are using reflection to do it Maybe we can come up with a better solution.



  • mok

    This (post) is a good question: 

    "Does reflection fall short when there is a need for dynamically creating a type occurs; such as a generic dictionary types. As found during an enumeration of the target object."

     The following example is as close as I could get. The constraint is that you have to know ahead of time the type associated to the dictionary. If you know that, this turns into a switch statement:


    Dictionary<string, string> genList = new Dictionary<string, string>();

    genList.Add("Hello", "World");
    genList.Add("Hash", "Table");

    Type itsType = genList.GetType();

    Console.WriteLine("Is this a generic type {0}", itsType.IsGenericType); // True
    Console.WriteLine("Is this a generic type definition {0}", itsType.IsGenericTypeDefinition); // false

    Type[] typeParameters = itsType.GetGenericArguments();

    Console.WriteLine(" List {0} type arguments:", typeParameters.Length);
    foreach (Type tParam in typeParameters)
    Console.WriteLine(" Type argument: {0}", tParam);

    if ((typeParameters[0] == typeof(string)) || (typeParameters[1] == typeof(string)))
    {
    IEnumerable intToDictionary = genList; // Cast to IEnumerable

    StringBuilder sb = new StringBuilder();

    foreach (KeyValuePair<string, string> item in intToDictionary)
    sb.AppendFormat("{0}\t{1}{2}",
    item.Value,
    item.Key,
    System.Environment.NewLine);

    Console.WriteLine(sb.ToString());
    }



    output:

    Is this a generic type True
    Is this a generic type definition False
    List 2 type arguments:
    Type argument: System.String
    Type argument: System.String
    World Hello
    Table Hash


  • Tom Michaels

    Check out the following members of the type class, they might point you in the right direction:

    ContainsGenericParameters
    GenericParameterAttributes
    GenericParameterPosition
    IsGenericParameter
    IsGenericType
    IsGenericTypeDefinition
    GetGenericArguments
    GetGenericParameterConstraints
    GetGenericTypeDefinition

    Using these member you should be able to query the instance of KeyValuePair that you get back to determine the types of its Key and Value properties



  • Seericssop

    Don't know nearly enough about it. But: try querying the type for the IDictionary interface instead of the IEnumerable interface.



  • Patrick Sears

    See my further explanation just posted. I see how your code works. But can you get the key and value of each entry without assume the type <string, string> For example, do some add after new Holder():

    hl.Add(“key1”, “value1”);

    Then in the main code can you get the keys and values back without assume you know the dictionary type Use reflection only.


  • PSRibeiro

    Thanks! This is one step closer to my target. I don't know how many types will be involved in the dictionary.


  • yelhsawm

    Why didn't you say so <g>... albeit I may not understand the problem, but to determine what a dictionary object is..,,try this on for size. I have two classes in a console app,

    public class Holder
    {

    public Dictionary<string, string> abc = new Dictionary<string, string>();


    }

    class Progam
    {


    static void Main(string[] args)
    {
    Holder hl = new Holder();
    FieldInfo[] myFieldInfo;

    Type myType = typeof(Holder);

    // Get the type and fields of FieldInfoClass.
    myFieldInfo = myType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance| BindingFlags.Public);
    Console.WriteLine("\nThe fields of " +"FieldInfoClass are \n");

    // Display the field information of FieldInfoClass.
    for (int i = 0; i < myFieldInfo.Length; i++)
    {
    Console.WriteLine("\nName : {0}", myFieldInfo[ i ].Name);
    Console.WriteLine("Declaring Type : {0}", myFieldInfo[ i ].DeclaringType);
    Console.WriteLine("IsPublic : {0}", myFieldInfo[ i ].IsPublic);
    Console.WriteLine("MemberType : {0}", myFieldInfo[ i ].MemberType);
    Console.WriteLine("FieldType : {0}", myFieldInfo[ i ].FieldType);
    Console.WriteLine("IsFamily : {0}", myFieldInfo[ i ].IsFamily);
    }

    }
    }

    When it prints out the Fieldtype, that reports:

    The fields of FieldInfoClass are

    Name : abc
    Declaring Type : ConsoleApplication1.Holder
    IsPublic : True
    MemberType : Field
    FieldType : System.Collections.Generic.Dictionary`2[System.String,System.String]
    IsFamily : False

    Good luck.


  • SkyMike99

    I am trying to write a code that works on some runtime classes which I have no control with. I want to be able to tell the field names, types and values of those classes. With this capability I want to finally compare two instances of the same type and record the differences. For example I want to write a function like this:

    void GetObjectDifference(object obj1, object obj2)

    where obj1 and obj2 are independent instances of the same complex type.

    The output of this function will be an xml file that describes the difference to very detail. So far, I have come to a point that my code works fine with primitive, string, value type, list, hash table and so on. But when a field is of type Dictionary<TKey, TValue>, then I have problem to tell its contained keys and values, since I can not cast the entries to a known type, such as DictionaryEntry or Dictionary<object, object>. I also could not find a powerful system utility function that is similar to FieldInfo.GetVaue, but can do something like EntryInfo.GetKey.

    Is this explanation better


  • ofa

    The piece of code that I working on has to use reflection. I don't even know the entry type. Can not assume it is KeyValuePair<string, string>. Thanks!
  • Bruce H

    Interesting things! But how do you use boundKvp in the red area of foreach Or how else it could help

    foreach (KeyValuePair<int, string> kvp in myDictionary)


  • How to get Dictionary<Tkey, TValue> entry information through reflection?