web-dev-qa-db-fra.com

Comment vérifier si une variable est un IEnumerable d'une sorte

en gros, je construis un modèle T4 très générique et l'une des choses dont j'ai besoin pour le faire est de dire print variable.ToString(). Cependant, je veux qu'il évalue les listes et les parcoure et imprime à la place ListItem.ToString() Mon modèle T4 ne sait pas quel type variable sera à l'avance, c'est pourquoi c'est si générique.

Mais mon code actuel qui est généré ressemble à ceci:

if(variable!=null)
  if(variable is IEnumerable) //error here
    foreach(var item in variable)
      Write(item.ToString());

J'obtiens une erreur de compilation sur la ligne marquée pour "L'utilisation du type générique System.Generic.Collections.IEnumerable nécessite un argument de type"

Je ne me soucie pas vraiment de quel type il s'agit, je veux juste savoir si vous pouvez foreach à travers la variable. Quel code dois-je utiliser à la place?

44
Earlz

Vous avez cependant déjà accepté une réponse, car le générique IEnumerable<T> implémente le IEnumerable non générique que vous pouvez simplement transtyper en cela.

// Does write handle null? Might need some sanity aswell.

var enumerable = variable as System.Collections.IEnumerable; 

if (enumerable != null)
    foreach(var item in enumerable)
         Write(item);
else
    Write(item);     
60
Courtney D

Si vous voulez tester le non générique IEnumerable alors vous devrez inclure un using System.Collections directive en haut de votre fichier source.

Si vous souhaitez tester un IEnumerable<T> d'une certaine sorte alors vous aurez besoin de quelque chose comme ça à la place:

if (variable != null)
{
    if (variable.GetType().GetInterfaces().Any(
            i => i.IsGenericType &&
            i.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
    {
        // foreach...
    }
}
21
LukeH

Les autres réponses ont souligné la différence IEnumerable générique/non générique, mais je dois également souligner que vous voudrez également tester spécifiquement String car il implémente IEnumerable, mais je doute que vous souhaitiez le traiter comme une collection de caractères.

14
Josh

Depuis C # 7.0, vous pouvez également réaliser ceci ainsi:

if (variable is IEnumerable enumVar)
{
    foreach (var e in enumVar)
    {
        ...
    }
}
4
Tobi

Eh bien, un peu simple mais ... si vous avez seulement:

using System.Collections.Generic;

vous devrez peut-être ajouter:

using System.Collections;

Le premier définit IEnumerable<T> et ce dernier définit IEnumerable.

3
Schultz9999

Dans général , sans type/interface de base non générique, cela nécessite GetType et une recherche récursive à travers la base types/interfaces.

Cependant , cela ne s'applique pas ici :-) Utilisez simplement le IEnumerable non générique (System.Collections.IEnumerable), dont IEnumerable générique (System.Collections.Generic.IEnumerable<T>) hérite.

2
user166390

Vous pouvez réellement tester directement la classe de base de tout type générique.

instance.GetGenericTypeDefinition()  == typeof(IEnumerable<>)
2
Rob Deary

Si vous ne vous souciez pas du type d'objet et que vous n'êtes pas dans la méthode générique dans C # 7.0+

        if (item is IEnumerable<object> enumVar)
        {
            foreach (var e in enumVar)
            {
                    e.ToString();

            }
        }

En C # <7,0

        if (item is IEnumerable<object>)
        {
            var enumVar = item as IEnumerable<object>;
            foreach (var e in enumVar)
            {
                e.ToString();

            }
            //or you can cast an array to set values, 
            //since IEnumerable won't let you, unless you cast to IList :) 
            //but array version here 
            //https://stackoverflow.com/a/9783253/1818723
        }
0
Pawel Cioch