6
votes

Keyvaluepair est l'objet énumérable?

Comment comprendre de manière programmatique si un objet dans une paire de valeur clé est énumérable?

J'ai besoin de savoir si un objet dans le champ Valeur est une liste ou une matrice. Je devrais pouvoir déterminer quel type de type énumérable l'objet est (par exemple, une liste de chaînes ou un ensemble d'INTS) xxx

ce que j'ai essayé:

1) xxx

2) xxx


0 commentaires

3 Réponses :


1
votes

Vous devez examiner les interfaces implémentées de kvp.value code>. Ceci n'est possible que par la réflexion.

var type = kvp.Value.GetType();
if (type.IsArray) return type.GetElementType();
foreach (var i in type.GetInterfaces())
{
    if (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))
    {
        return i.GetGenericTypeArguments()[0];
    }
}
// not a generic collection
return typeof(object);


1 commentaires

GetGenerictypearguments n'est pas accessible, vous devez utiliser getgenericarguments . BTW, le vôtre fonctionne bien.



1
votes

Ceci fonctionne pour les types les plus énumérables:

Type objListType = null;

if (kvp.Value is IEnumerable) {

    if (kvp.Value.GetType().IsArray) 
        objListType = kvp.Value.GetType().GetElementType();
    else
        objListType = kvp.Value.GetType().GetProperty("Item").PropertyType;

}


6 commentaires

@Georg ouais, j'ai écrit la plupart


@Aneves je l'utilise pour les listes


@Aneves Vous devez inclure une déclaration à l'aide de System.Collections


Vrai; Je l'avais seulement pour system.collections.generic .


@Teejay Oui, mais dans mes ensembles d'opinions sont une classe de collections très importante (bien que Microsoft ait apparemment un avis différent). Votre approche n'est valable que pour les listes


@Georg OP a demandé au tableau et aux listes. Cela marche. BTW ça marche sur plusieurs types énumérables.



3
votes

en utilisant dynamique code> strong>

Vous pouvez tirer parti du mot clé code> dynamique de code> pour faire cela, mais je pense que cela pourrait être trop lent pour vous. P>

Cependant, voici comment vous pourriez le faire. Ceci appellera une méthode énumérer fortement typée () code> pour la liste code> et t [] code> ou si la valeur n'est ni une liste ni un tableau, il appellera la surcharge de énumérer () code> qui prend simplement un objet. p>

Je ne suis pas entiellement sûr que c'est ce que vous êtes après, mais cela donne vous une énumération fortement typée des listes et des tableaux dans votre liste KVP. p>

Notez que conformément à votre spécification, celle-ci considère uniquement la liste et les types de réseau; Les autres types énumérables (tels que les chaînes, le hashset etc.) ne sont pas pris en compte: p> xxx pré>


en utilisant une réflexion explicite forte> p> Voici une façon de le faire à l'aide de la réflexion qui évite d'utiliser dynamique code>, ce qui signifie que c'est beaucoup plus rapide - mais comme vous pouvez le constater, il est significativement plus fiddlois! p>

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

namespace ConsoleApp1
{
    sealed class Program
    {
        void test()
        {
            List<KeyValuePair<string, object>> lKVP = new List<KeyValuePair<string, object>>();
            List<string> lS = new List<string> { "s1", "s2" };
            string[] aS = {"a1", "a2"};

            lKVP.Add(new KeyValuePair<string, object>("String", "E92D8719-38A6-0000-961F-0E66FCB0A363"));
            lKVP.Add(new KeyValuePair<string, object>("Test", lS));
            lKVP.Add(new KeyValuePair<string, object>("IntNotEnumerable", 12345));
            lKVP.Add(new KeyValuePair<string, object>("Array", aS));

            var listEnumerator  = this.GetType().GetMethod("enumerateList",  BindingFlags.NonPublic | BindingFlags.Static);
            var arrayEnumerator = this.GetType().GetMethod("enumerateArray", BindingFlags.NonPublic | BindingFlags.Static);

            foreach (KeyValuePair<string, object> kvp in lKVP)
            {
                MethodInfo genericEnumerator = null;
                var arrayElemType = arrayElementType(kvp.Value);

                if (arrayElemType != null)
                {
                    genericEnumerator = arrayEnumerator.MakeGenericMethod(arrayElemType);
                }
                else
                {
                    var listElemType = listElementType(kvp.Value);

                    if (listElemType != null)
                        genericEnumerator = listEnumerator.MakeGenericMethod(listElemType);
                }

                if (genericEnumerator != null)
                    genericEnumerator.Invoke(null, new[] { kvp.Value });
                else
                    Console.WriteLine("Not enumerating type: " + kvp.Value.GetType().FullName + "\n");
            }
        }

        static Type arrayElementType(object sequence)
        {
            if (sequence is IEnumerable)
            {
                var type = sequence.GetType();

                if (type.IsArray)
                    return type.GetElementType();
            }

            return null;
        }

        static Type listElementType(object sequence)
        {
            if (sequence is IEnumerable)
            {
                var type = sequence.GetType();

                if (typeof(IList).IsAssignableFrom(type) && type.IsGenericType)
                    return type.GetProperty("Item").PropertyType;
            }

            return null;
        }

        static void enumerateList<T>(List<T> list)
        {
            Console.WriteLine("Enumerating list of " + typeof(T).FullName);

            foreach (var item in list)
                Console.WriteLine(item);

            Console.WriteLine();
        }

        static void enumerateArray<T>(T[] array)
        {
            Console.WriteLine("Enumerating array of " + typeof(T).FullName);

            foreach (var item in array)
                Console.WriteLine(item);

            Console.WriteLine();
        }

        static void Main(string[] args)
        {
            new Program().test();
        }
    }
}


3 commentaires

Lorsque vous utilisez votre code de réflexion, je reçois une référence d'objet non envoyée à une instance d'un objet sur la ligne généricenumerator = listumerator.MakeGenericMethod (ListelemType);


@Bossross Vous n'obtiendrez pas cette erreur lorsque vous exécutez mon code d'échantillon sans aucune modification. Si vous obtenez cette erreur lorsque vous avez modifié le code, c'est qu'il n'y a pas de méthode privée statique appelée «énumérateliste» dans la classe, et donc getMethod () retourne null. Vous devrez modifier cet appel pour spécifier le nom de méthode approprié et les indicateurs de liaison pour la méthode que vous souhaitez appeler.


J'ai utilisé le code de réflexion, cela fonctionne bien (lorsque les bonnes méthodes sont statiques), merci de l'aide et de la bonne réponse