Enum [] является IEnumerable <int> возвращает true в общем методе

Это следующий вопрос к этому вопросу: Cast <int> .Cast < int? > применяется для генерации общих результатов перечисления в недействительном личном исключении

enum Gender { Male, Female }

Gender g = Gender.Male;

bool b = g is int; // false, alright no issues
b = new[] { g } is IEnumerable<int>; // false, alright no issues
b = Is<Gender, int>(g); //false, alright no issues
b = Is<Gender[], IEnumerable<int>>(new[] { g }); // true, why on earth !!!

static bool Is<S, T>(S s)
{
    return s is T;
}

Почему это Gender[] is IEnumerable<int> возвращает true в общем случае? Особенно, если они не совместимы с типом?

IEnumerable<int> c = new[] { Gender.Male }; //not compilable

Это смутило меня в вопросе, который я связал! Я думаю, что этот вопрос является основной проблемой связанного вопроса.


Для кого-то, кого это интересует, это угловой случай с массивами (на самом деле нет перечислений). Следуйте блог Эрика Липперта в ответ, чтобы узнать больше об этом случае. Это не происходит с List<T>, например:

b = Is<List<Gender>, IEnumerable<int>>(new List<Gender> { g }); // false, rightly

Ответы

Ответ 1

Я думаю, что это один из тех случаев, когда определение С# is отличается от определения CLI isinst, которое, по-видимому, рассматривает перечисления как их базовый тип при проверке совместимости присвоений массивов. (Эрик Липперт написал сообщение в блоге, в котором объясняется, почему uint[] рассматривается как int[] CLI, но не С#; я подозреваю, что здесь применяется такое же объяснение. ) Вам даже не нужны дженерики, чтобы продемонстрировать:

Gender g = Gender.Male;
Console.WriteLine(new[] { g } is IEnumerable<int>); // False
Console.WriteLine((object)new[] { g } is IEnumerable<int>); // True

Первое выражение is оптимизировано на false во время компиляции, потому что компилятор С# "знает" Gender[] не является IEnumerable<int>. Второе выражение is генерирует инструкцию isinst, которая оценивается во время выполнения. Цитирование Эрика Липперта:

К сожалению, спецификации С# и CLI не согласны с этой незначительной точкой, но мы готовы жить с несогласованностью.