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

发布于 2024-08-13 23:05:48 字数 1029 浏览 2 评论 0原文

我想知道为什么到枚举值的单个隐式转换的工作方式与转换到系统类型时的工作方式不同。我看不出任何技术原因,但也许比我聪明的人可以为我提供一些启发。

以下代码无法使用“需要整数类型的值”“无法将类型'Test.En'隐式转换为'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、字符,字符串。如果不存在此类隐式转换,或者存在多个此类隐式转换,则会发生编译时错误。

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

I am wondering why it is that a single implicit conversion to an enum value doesn't work the same way it would if the conversion were to a system type. I can't see any technical reason however maybe someone smarter than I can shed some light for me.

The followoing fails to compile with, "A value of an integral type expected" and "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;
    }
}

edit from the spec:

The governing type of a switch statement is established by the switch expression. If the type of the switch expression is sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or an enum-type, then that is the governing type of the switch statement. Otherwise, exactly one user-defined implicit conversion (§6.4) must exist from the type of the switch expression to one of the following possible governing types: sbyte, byte, short, ushort, int, uint, long, ulong, char, string. If no such implicit conversion exists, or if more than one such implicit conversion exists, a compile-time error occurs.

To Clarify the question, why is an enum-type not included with the list of allowed user-defined implicit conversions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

绝影如岚 2024-08-20 23:05:48

语言设计说明存档没有提供此决定的理由。这是不幸的,因为决定改变了。正如您所看到的,该设计随着时间的推移而演变:

1999 年 5 月 26 日的注释:

允许使用哪些类型
switch 语句的参数?
整型包括 char、enum
类型,布尔。 C# 也允许类型
这可以隐含地并且
明确转换为其中之一
上述类型。 (如果有
多次隐式转换,那么它的
不明确且编译时错误
发生。)我们不确定我们是否
是否支持字符串。

1999 年 6 月 7 日:

我们讨论了启用字符串开关
论据。我们认为这是一个很好的
特性——语言可以增加价值
通过使这种常见情况更容易
写,以及额外的复杂性
对于用户来说是非常低的。

1999 年 12 月 20 日:

开机是违法的
bool 类型的表达式。这是合法的
打开 a 的表达式
整型或字符串类型。这是
打开 a 的表达式是合法的
只具有一个隐式的类型
转换为整型或
字符串类型。

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

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

几年后,2003 年 8 月 13 日的

编译器允许布尔值切换。
不想记录并添加它
到语言。不想删除
出于兼容性原因。决定了
默默继续支持switch
在布尔值上。

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

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

The language design notes archive does not provide a justification for this decision. This is unfortunate, since the decision was changed. As you can see, the design evolved over time:

Notes from May 26th, 1999:

What types are allowed in as the
argument to a switch statement?
integral types including char, enum
types, bool. C# also permits types
that can be implicitly and
unambiguously converted to one of the
aforementioned types. (If there are
multiple implicit conversion, then its
ambiguous and a compile-time error
occurs.) We're not sure whether we
want to support string or not.

June 7th, 1999:

We discussed enabling switch on string
arguments. We think this is a good
feature – the language can add value
by making this common case easier to
write, and the additional complexity
for the user is very low.

December 20th, 1999:

It is illegal to switch on an
expression of type bool. It is legal
to switch on an expression of an
integral type or string type. It is
legal to switch on an expression of a
type that has exactly one implicit
conversion to an integral type or
string type.

Here we have the first occurence of the rule in question. Enums seem to have disappeared. And why not use user-defined implicit conversions to enum? Was this simply an oversight? The designers did not record their thoughts.

Note that the first sentence is NOT what we implemented. It is unclear to me why the implementors did the opposite of what the design committee recommended. This comes up again in the notes several years later:

August 13, 2003:

The compiler allows switch on bool.
Don’t want to document this and add it
to the language. Don’t want to remove
it for compatibility reasons. Decided
to silently continue to support switch
on bool.

I decided that this was silly; when we produced the annotated print edition of the C# 3.0 specification, I added bool (and bool?) to the list of legal governing types.

In short: the whole thing is a bit of a mess. I have no idea why enums were in, then out, then half-in-half-out. This might have to remain one of the Mysteries of the Unknown.

末蓝 2024-08-20 23:05:48

因为出于切换的目的,枚举被视为整数,并且正如我之前所问的,编译器不会执行多次隐式转换来获取可用类型,它无法弄清楚如何打开 foo。

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

我编译然后反映了你的代码,结果如下:

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

所以显然在幕后它确实做了隐式转换。 :S

Because enums are treated as integers for the purpose of switching, and as i've asked before, the compiler doesn't do multiple implicit conversions to get to a usable type, it can't figure out how to switch on foo.

My only theory as to why enums can't be used like that is that enums are not an integer type in and of themselves, and thus the compiler would have to do multiple implicit conversions to get to an integer primitive from foo.

I compiled then reflected your code and here's the results:

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

So apparently under the covers it does do an implicit conversion. :S

等风来 2024-08-20 23:05:48
void test1 (){
   Foo f = new Foo();
   En n = f;

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

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

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

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

EDIT: Since switch expects an integral value, writing switch(f) makes the compiler look for conversion from an instance of Foo to an integral type, which doesn't exist.

睫毛上残留的泪 2024-08-20 23:05:48

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

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

What if your class contained two enums and had implicit conversion operators for both? Or better yet, what if you had implicit conversion operators for an enum and int? Which conversion would the compiler "automatically" pick for you when you write a switch statement?

You have to explicitly specify what type of object is being used inside the switch statement. Implicit operators just tell the compiler/runtime "if you have a Foo and need an En, this code does that". It does not change the actual underlying type of the object.

懵少女 2024-08-20 23:05:48

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

作为一个兴趣点,它的表现如何?

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

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

Take a look at that second error message. The compiler is trying to type-coerce the enum to match the type of what is in the switch statement.

As a point of interest, how does this fare?

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

    switch (En.One)
    {
        case f:
            break;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文