C# 为什么可以';使用到枚举的单个隐式转换打开类

C# 为什么可以';使用到枚举的单个隐式转换打开类,c#,switch-statement,enums,C#,Switch Statement,Enums,我想知道为什么到枚举值的单个隐式转换与到系统类型的转换的工作方式不同。我看不出任何技术上的原因,但是也许有比我更聪明的人能为我带来一些启示 下面的代码无法编译,“需要整数类型的值”,“无法隐式地将类型“Test.En”转换为“Test.Foo” 编辑规范中的: switch语句的控制类型由switch表达式建立。如果switch表达式的类型是sbyte、byte、short、ushort、int、uint、long、ulong、char、string或枚举类型,则这是switch语句的控制类型。

我想知道为什么到枚举值的单个隐式转换与到系统类型的转换的工作方式不同。我看不出任何技术上的原因,但是也许有比我更聪明的人能为我带来一些启示

下面的代码无法编译,
“需要整数类型的值”
“无法隐式地将类型“Test.En”转换为“Test.Foo”

编辑规范中的

switch语句的控制类型由switch表达式建立。如果switch表达式的类型是sbyte、byte、short、ushort、int、uint、long、ulong、char、string或枚举类型,则这是switch语句的控制类型。否则,从开关表达式的类型到以下可能的控制类型之一,必须存在一个用户定义的隐式转换(§6.4):sbyte、byte、short、ushort、int、uint、long、ulong、char、string。如果不存在此类隐式转换,或者存在多个此类隐式转换,则会发生编译时错误


为了澄清这个问题,为什么允许的用户定义隐式转换列表中不包括枚举类型?

请查看第二条错误消息。编译器正在尝试类型强制枚举与switch语句中的类型匹配

作为一个兴趣点,这是怎么回事

void test2 (){
    Foo f = new Foo();

    switch (En.One)
    {
        case f:
            break;
    }
}

因为为了切换,枚举被视为整数,正如我之前所问的,它不知道如何切换到foo

关于枚举不能这样使用的原因,我唯一的理论是枚举本身不是整数类型,因此编译器必须进行多次隐式转换才能从foo获得整数原语

我编译了你的代码,结果如下:

public static void Main()
{
    Foo f = new Foo();
    f._myEn = En.Three;
    switch (f)
    {
        case En.One:
        {
        }
    }
}

因此,显然在封面下,它确实进行了隐式转换S

如果您的类包含两个枚举,并且两个枚举都有隐式转换运算符,该怎么办?或者更好的是,如果对枚举和int使用隐式转换运算符会怎么样?编写switch语句时,编译器会“自动”为您选择哪种转换

必须明确指定在switch语句中使用的对象类型。隐式操作符只告诉编译器/运行时“如果您有一个Foo并且需要一个En,那么这段代码就可以做到”。它不会更改对象的实际基础类型

void test1 (){
   Foo f = new Foo();
   En n = f;

    switch (n)
    {
        case En.One:
            break;
    }
}

编辑:由于
switch
需要一个整型值,因此编写
switch(f)
会使编译器寻找从
Foo
实例到不存在的整型的转换。

语言设计说明存档文件不会为该决定提供理由。这是不幸的,因为决定被改变了。如您所见,设计随着时间的推移而演变:

1999年5月26日的注释:

允许哪些类型作为 switch语句的参数? 整数类型,包括char、enum 类型,布尔。C#也允许类型 这可以是隐式的和 明确地转换为 上述类型。(如果有 多重隐式转换,然后 不明确和编译时错误 我们不确定是否 是否要支持字符串

1999年6月7日:

我们讨论了启用字符串上的开关 论据。我们认为这是一个好机会 功能–语言可以增加价值 通过使这一常见案例更容易理解 写,以及额外的复杂性 对于用户来说是非常低的

1999年12月20日:

打开电源是违法的 布尔型表达式。这是合法的 打开 整型或字符串型。它是 打开表达式的合法操作 只有一个隐式 转换为整型或整型 字符串类型

在这里,我们有第一次出现的规则的问题。枚举似乎已经消失了。为什么不使用用户定义的隐式转换来枚举呢?这仅仅是一个疏忽吗?设计师没有记录他们的想法

请注意,第一句话不是我们实现的。我不清楚为什么实施者做了与设计委员会建议相反的事情。几年后的笔记中再次提到这一点:

二○○三年八月十三日:

编译器允许打开bool。 不想记录此内容并添加它 与语言相适应。不想删除 这是出于兼容性的原因。果断的 要继续支持交换机,请执行以下操作: 在布尔

我觉得这很愚蠢;当我们制作C#3.0规范的带注释的印刷版时,我将bool(和bool?)添加到合法管理类型列表中


简言之:整个事情有点乱。我不知道为什么enum是先入后出,然后半对半出的。这可能仍然是未知之谜之一。

case Foo.En.one?需要查看代码的其余部分,但这看起来像是正确指定类型名称的简单示例。因为您不应该懒惰:)需要Eric Lippert时他在哪里?:)这将失败,因为case后面必须跟一个常量表达式。“因为枚举被视为整数用于切换”-如果您认为在那里执行了实际转换(就语言语义而言,而不是VC#的实现细节而言),那么请引用规范。我在规范中找不到任何关于它的内容,但这是我最好的猜测。Reflector在反编译时给了我一些有趣的东西,我将在上面发布我的结果。你是说当你在开关“switch((En)f)”中使用显式转换来反映编译后的版本时,它看起来是这样的吗?(我添加了foo的枚举赋值)当我使用Reflector时,转换仍然存在。虽然在查看IL时,我看不到第二次转换(从En到int)-这表示
void test1 (){
   Foo f = new Foo();
   En n = f;

    switch (n)
    {
        case En.One:
            break;
    }
}