Ранее принятый ответ это хорошо, но это неправильно. К счастью, ошибка маленькая. Проверка на IEnumerable
не достаточна, если вы действительно хотите узнать об общей версии интерфейса; Есть много классов, которые реализуют только неуниверсальный интерфейс. Я дам ответ через минуту. Во-первых, я хотел бы отметить, что принятый ответ слишком сложен, поскольку следующий код достиг бы того же в данных обстоятельствах:
if (items[key] is IEnumerable)
Это делает еще больше, потому что работает для каждого элемента в отдельности (а не для их общего подкласса, V
).
Теперь за правильное решение. Это немного сложнее, потому что мы должны взять универсальный тип IEnumerable`1
(то есть тип IEnumerable<>
с одним параметром типа) и ввести правильный универсальный аргумент:
static bool IsGenericEnumerable(Type t) {
var genArgs = t.GetGenericArguments();
if (genArgs.Length == 1 &&
typeof(IEnumerable<>).MakeGenericType(genArgs).IsAssignableFrom(t))
return true;
else
return t.BaseType != null && IsGenericEnumerable(t.BaseType);
}
Вы можете легко проверить правильность этого кода:
var xs = new List<string>();
var ys = new System.Collections.ArrayList();
Console.WriteLine(IsGenericEnumerable(xs.GetType()));
Console.WriteLine(IsGenericEnumerable(ys.GetType()));
дает:
True
False
Не слишком переживайте из-за того, что здесь используется отражение. Хотя это правда, что это увеличивает накладные расходы во время выполнения, также как и использование оператора is
.
Конечно, приведенный выше код ужасно ограничен и может быть расширен в более общеприменимый метод IsAssignableToGenericType
. Следующая реализация немного некорректна 1 , и я оставлю ее здесь только для исторических целей . Не используйте его . Вместо этого Джеймс предоставил превосходную, правильную реализацию в своем ответе.
public static bool IsAssignableToGenericType(Type givenType, Type genericType) {
var interfaceTypes = givenType.GetInterfaces();
foreach (var it in interfaceTypes)
if (it.IsGenericType)
if (it.GetGenericTypeDefinition() == genericType) return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return baseType.IsGenericType &&
baseType.GetGenericTypeDefinition() == genericType ||
IsAssignableToGenericType(baseType, genericType);
}
1 Сбой, когда genericType
совпадает с givenType
; по той же самой причине, это терпит неудачу для обнуляемых типов, то есть
IsAssignableToGenericType(typeof(List<int>), typeof(List<>)) == false
IsAssignableToGenericType(typeof(int?), typeof(Nullable<>)) == false
Я создал сущность с полным набором тестовых случаев .