enum []是IEnumerable <int>在泛型方法中返回true

naw*_*fal 15 c# generics enums typechecking

这是此问题的后续内容:对通用枚举集合应用的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;
}
Run Code Online (Sandbox Code Playgroud)

为什么在一般情况下Gender[] is IEnumerable<int>返回true?特别是当它们不兼容时?

IEnumerable<int> c = new[] { Gender.Male }; //not compilable
Run Code Online (Sandbox Code Playgroud)

在我链接的问题中,它让我感到惊讶!我认为这个问题是相关问题问题的症结所在.


对于有兴趣的人来说,这是一个带有数组(不是真正的枚举)的极端情况.在答案中关注Eric Lippert的博客文章,了解更多这个边缘案例.例如,这不会发生List<T>:

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

Mic*_*Liu 15

我认为这是C#定义is与CLI 定义不同的情况之一isinst,在检查数组赋值兼容性时,它显然将枚举视为其底层基类型.(Eric Lippert撰写了一篇博客文章,解释了为什么uint[]int[]CLI 视为一种,而不是C#;我怀疑同样的解释适用于此.)你甚至不需要泛型来证明:

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

第一个is表达式false编译时被优化,因为C#编译器"know" Gender[]不是IEnumerable<int>.第二个is表达式生成一个isinst运行时计算的指令.引用Eric Lippert:

遗憾的是C#和CLI规范在这个小问题上存在分歧,但我们愿意忍受不一致.

  • 这是Eric的帖子:http://blogs.msdn.com/b/ericlippert/archive/2009/09/24/why-is-covariance-of-value-typed-arrays-inconsistent.aspx (2认同)