繁体   English   中英

为什么我不能通过单个隐式转换为枚举来打开类

[英]Why can't I switch on a class with a single implicit conversion to an enum

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

后续编译无法编译, "A value of an integral type expected""Cannot implicitly convert type 'Test.En' to 'Test.Foo"

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

    switch (f)         // Comment this line to compile
    //switch ((En)f)   // Uncomment this line to compile
    {
        case En.One:
            break;
    }
}


//////////////////////////////////////////////////////////////////

public enum En
{
    One,
    Two,
    Three,
}

public class Foo
{
    En _myEn;

    public static implicit operator En(Foo f)
    {
        return f._myEn;
    }
}

从规范编辑

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

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

语言设计说明存档不能为此决策提供理由。 这是不幸的,因为决定已经改变。 如您所见,设计随着时间的推移而发展:

1999年5月26日的笔记:

允许哪些类型作为switch语句的参数? 整数类型包括char,enum类型,bool。 C#还允许可以隐式和明确地转换为上述类型之一的类型。 (如果存在多个隐式转换,则会发生其模糊和编译时错误。)我们不确定是否要支持字符串。

1999年6月7日:

我们讨论了启用字符串参数的开关。 我们认为这是一个很好的功能 - 语言可以通过使这种常见情况更容易编写来增加价值,并且用户的额外复杂性非常低。

1999年12月20日:

打开bool类型的表达式是非法的。 打开整数类型或字符串类型的表达式是合法的。 打开一个类型的表达式是合法的,该表达式只有一个隐式转换为整数类型或字符串类型。

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

请注意,第一句话不是我们实施的。 我不清楚为什么实现者与设计委员会推荐的相反。 几年之后,这在笔记中又出现了:

2003年8月13日:

编译器允许切换bool。 不想记录此内容并将其添加到语言中。 出于兼容性原因,不希望将其删除。 决定默默地继续支持切换bool。

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

简而言之:整件事情有点混乱。 我不知道为什么枚举进入,然后出局,然后是半成半。 这可能必须是未知之谜之一。

因为枚举被视为整数以便进行切换,并且正如我之前所要求的那样, 编译器不会进行多次隐式转换以获得可用类型 ,因此无法弄清楚如何启用foo。

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

我编译然后反映了你的代码,这里是结果:

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

显然,它隐藏在转换中。 :S

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

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

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

看一下第二条错误消息。 编译器正在尝试对枚举进行类型强制以匹配switch语句中的类型。

作为一个兴趣点,这个票价怎么样?

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM