Как проверить, является ли переменная IEnumerable какой-то - PullRequest
40 голосов
/ 04 января 2011

В основном я создаю очень общий шаблон T4, и одна из вещей, которые мне нужны, это сказать print variable.ToString().Тем не менее, я хочу, чтобы он оценивал списки и просматривал их, а вместо этого печатал ListItem.ToString() Мой шаблон T4 не знает, какой тип variable будет опережать время, поэтому он настолько универсален.

Номой текущий генерируемый код выглядит следующим образом:

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

Я получаю ошибку компилятора в отмеченной строке для «Использование универсального типа System.Generic.Collections.IEnumerable требует один аргумент типа»

На самом деле мне все равно, какой это тип, я просто хочу знать, можете ли вы использовать foreach через переменную.Какой код я должен использовать вместо этого?

Ответы [ 8 ]

58 голосов
/ 04 января 2011

Вы уже приняли ответ, так как универсальный IEnumerable<T> реализует неуниверсальный IEnumerable, который вы можете просто привести к нему.

// 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);     
21 голосов
/ 04 января 2011

Если вы хотите проверить неуниверсальный IEnumerable, вам нужно будет включить директиву using System.Collections в верхней части исходного файла.

Если выхотите проверить на IEnumerable<T>, тогда вам нужно что-то вроде этого:

if (variable != null)
{
    if (variable.GetType().GetInterfaces().Any(
            i => i.IsGenericType &&
            i.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
    {
        // foreach...
    }
}
14 голосов
/ 04 января 2011

В других ответах указывалось на общее / неуниверсальное различие IEnumerable, но я также должен отметить, что вы также захотите проверить его на String, поскольку он реализует IEnumerable, но я сомневаюсь, что вы захотите рассматривать его как коллекциюсимволов.

4 голосов
/ 08 января 2019

Начиная с C # 7.0, вы также можете достичь этого так:

if (variable is IEnumerable enumVar)
{
    foreach (var e in enumVar)
    {
        ...
    }
}
3 голосов
/ 04 января 2011

Ну, несколько просто, но ... если у вас есть только:

using System.Collections.Generic;

вам может понадобиться добавить:

using System.Collections;

Первый определяет IEnumerable<T>, а второй определяет IEnumerable.

2 голосов
/ 14 июля 2015

Вы можете непосредственно протестировать базовый класс любого универсального типа.

instance.GetGenericTypeDefinition()  == typeof(IEnumerable<>)
2 голосов
/ 04 января 2011

В общем , без неуниверсального базового типа / интерфейса, для этого требуется GetType и рекурсивный просмотр базовых типов / интерфейсов.

Однако , что здесь не применимо :-) Просто используйте неуниверсальный IEnumerable (System.Collections.IEnumerable), от которого наследуется универсальный IEnumerable (System.Collections.Generic.IEnumerable<T>).

0 голосов
/ 18 апреля 2015

Это старый вопрос, но я хотел показать альтернативный метод определения, является ли SomeType IEnumerable:

var isEnumerable = (typeof(SomeType).Name == "IEnumerable`1");
...