Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate through an enumeration of KeyValuePair without knowing the type of the key and the type of the value

Tags:

Say I have a method like this:

public void Foo(object arguments)

and say I need to detect if the type of arguments is actually an enumeration. I would write something like this:

if (arguments is IEnumerable)

Now, let's say I need to detect if it's an enumeration of KeyValuePair (regardless of the type of the key and the type of the value). My instinct would be to write something like this:

if (arguments is IEnumerable<KeyValuePair<,>>)

but visual studio complains that Using the generic type 'KeyValuePair<TKey, TValue>' requires 2 type arguments.

I also tried:

if (arguments is IEnumerable<KeyValuePair<object, object>>)

but it returns false if the key is anything but an object (such as a string for example) or if the value is anything but an object (such as an int for example).

Does anybody have suggestions how I could determine if an enumeration contains KeyValuePairs regardless of the key type and the value type and if so, how can I loop through these pairs?

like image 909
desautelsj Avatar asked Dec 29 '17 03:12

desautelsj


People also ask

What defines a collection that consists of key-value pair?

A key-value pair consists of two related data elements: A key, which is a constant that defines the data set (e.g., gender, color, price), and a value, which is a variable that belongs to the set (e.g., male/female, green, 100). Fully formed, a key-value pair could look like these: gender = male. color = green.

What is the difference between KeyValuePair and dictionary C#?

KeyValuePair<TKey,TValue> is used in place of DictionaryEntry because it is generified. The advantage of using a KeyValuePair<TKey,TValue> is that we can give the compiler more information about what is in our dictionary. To expand on Chris' example (in which we have two dictionaries containing <string, int> pairs).

Can you foreach a dictionary C#?

In C# programming, we have different methods to iterate over the dictionary. The foreach loop method is also used for iterating over the dictionary. This article will discuss how to iterate over a dictionary using a foreach loop.

When would you use a key-value pair?

A key-value pair (KVP) is a set of two linked data items: a key, which is a unique identifier for some item of data, and the value, which is either the data that is identified or a pointer to the location of that data. Key-value pairs are frequently used in lookup tables, hash tables and configuration files.


1 Answers

You need some reflection here:

Boolean isKeyValuePair = false;

Type type = arguments.GetType();

if (type.IsGenericType)
{
    Type[] genericTypes = type.GetGenericArguments();

    if (genericTypes.Length == 1)
    {
        Type underlyingType = genericTypes[0];

        if (underlyingType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
            isKeyValuePair = true;
    }
}

In order to rebuild an Enumerable and iterate over it, you could use the following approach that uses dynamic:

List<KeyValuePair<Object, Object>> list = new List<KeyValuePair<Object, Object>>();

foreach (dynamic kvp in (IEnumerable)arguments)
    list.Add(new KeyValuePair<Object, Object>(kvp.Key, kvp.Value));

or, with LINQ:

List<KeyValuePair<Object, Object>> list = (from dynamic kvp in (IEnumerable)arguments select new KeyValuePair<Object, Object>(kvp.Key, kvp.Value)).ToList();

I also found another solution, but this is pure madness:

Boolean isKeyValuePair = false;

Type type = arguments.GetType();

if (type.IsGenericType)
{
    Type[] genericTypes = type.GetGenericArguments();

    if (genericTypes.Length == 1)
    {
        Type underlyingType = genericTypes[0];

        if (underlyingType.GetGenericTypeDefinition() == typeof (KeyValuePair<,>))
        {
            Type[] kvpTypes = underlyingType.GetGenericArguments();

            Type kvpType = typeof(KeyValuePair<,>);
            kvpType = kvpType.MakeGenericType(kvpTypes);

            Type listType = typeof (List<>);
            listType = listType.MakeGenericType(kvpType);

            dynamic list = Activator.CreateInstance(listType);

            foreach (dynamic argument in (IEnumerable)arguments)
                list.Add(Activator.CreateInstance(kvpType, argument.Key, argument.Value));
        }
    }
}

References:

  • Type.IsGenericType
  • Type.GetGenericArguments
  • Type.GetGenericTypeDefinition
like image 148
Tommaso Belluzzo Avatar answered Sep 22 '22 12:09

Tommaso Belluzzo