How to iterate over a KeyValuePair enumeration without knowing the key type and value type

Let's say I have a method like this:

public void Foo(object arguments)

and say that I need to determine if the type argumentsis really an enumeration. I would write something like this:

if (arguments is IEnumerable)

Now let's say I need to determine if this is an enumeration of KeyValuePair (regardless of the type of key and type of 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 returns false if the key is something like an object (for example string), or if the value is something like an object (for example int).

- , , KeyValuePairs , , ?

+4
3

- :

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

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

, LINQ:

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

, :

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

:

+1

GetGenericTypeDefinition

var pair = new KeyValuePair<string, int>("asd", 123);

var isOf = pair.GetType().GetGenericTypeDefinition() == typeof(KeyValuePair<,>);

. ,

InvalidOperationException

. , IsGenericType .

Type.IsGenericType

, , ,

foreach

private bool Get<T>(IEnumerable<T> list, Type someType) 
{
   foreach (var item in list)
   {
      if (item.GetType()
               .GetGenericTypeDefinition() == someType)
      {
         return true;
      }
   }
   return false;
}

private List<T> Get2<T>(IEnumerable<T> list, Type someType)
{
   return list.Where(
         item => item.GetType()
                     .GetGenericTypeDefinition() == someType)
      .ToList();
}}

var blah = Get2(list, typeof(KeyValuePair<,>));

. , , , , , .

.GetGenericTypeDefinition Method()

Type.IsGenericType

+1

@tommaso-belluzzo @sarumanfor , , . , Tommaso , dynamic .

( Tommasso)

/// <summary>Get the key=>value pairs represented by a dictionary, enumeration of KeyValue pairs or an anonymous object.</summary>
private IEnumerable<KeyValuePair<string, object>> GetArguments(object arguments)
{
    // null
    if (arguments == null)
        return Enumerable.Empty<KeyValuePair<string, object>>();

    // dictionary
    if (arguments is IDictionary dictionary)
        return dictionary
            .Cast<dynamic>()
            .Select(item => new KeyValuePair<string, object>(item.Key.ToString(), item.Value));

    // enumeration
    if (arguments is IEnumerable enumeration)
    {
#if NETFULL
        var argumentsType = enumeration.GetType();
        var itemType = argumentsType.GetElementType();
        var isGeneric = itemType.IsGenericType;
        var enumeratedType = isGeneric ? itemType.GetGenericTypeDefinition() : null;
#else
        var argumentsTypeInfo = enumeration.GetType().GetTypeInfo();
        var itemTypeInfo = argumentsTypeInfo.GetElementType().GetTypeInfo();
        var isGeneric = itemTypeInfo.IsGenericType;
        var enumeratedType = isGeneric ? itemTypeInfo.GetGenericTypeDefinition() : null;
#endif

        if (enumeratedType == typeof(KeyValuePair<,>))
        {
            return enumeration
                .Cast<dynamic>()
                .Select(item => new KeyValuePair<string, object>(item.Key.ToString(), item.Value));
        }
        else
        {
            throw new ArgumentException("You must provide an enumeration of KeyValuePair", nameof(arguments));
        }
    }

    // object
    return arguments.GetType()
        .GetRuntimeProperties()
        .Where(p => p.CanRead)
        .Select(p => new KeyValuePair<string, object>(p.Name, p.GetValue(arguments)));
}
0

Source: https://habr.com/ru/post/1691487/


All Articles