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

时间:2013-11-29 20:33:49

标签: c# generics enums typechecking

这是此问题的后续内容:Cast<int>.Cast<int?> applied on generic enum collection results in invalid cast exception

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

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


对于有兴趣的人来说,这是一个带阵列(不是真正的枚举)的极端情况。请按照答案中的Eric Lippert's blog文章了解更多此边缘案例。例如,List<T>不会发生这种情况:

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

1 个答案:

答案 0 :(得分:15)

我认为这是is的C#定义与CLI isinst的定义不同的情况之一,在查看数组赋值兼容性时,它显然将枚举视为其基础基类型。 (Eric Lippert编写了一个blog post,解释了为什么uint[]被CLI视为int[]而不是C#;我怀疑同样的解释适用于此。)你甚至不需要用于演示的泛型:

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

第一个is表达式在编译时优化为false,因为C#编译器“知道”Gender[]不是IEnumerable<int> 。第二个is表达式生成isinst指令,该指令在运行时进行评估。引用Eric Lippert:

  

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