为什么C#编译器允许空枚举?

为什么C#编译器允许空枚举?,c#,compiler-construction,enums,C#,Compiler Construction,Enums,我今天意外地定义了一个不包含任何值的枚举。比如这个: public enum MyConfusingEnum{} public enum Argb : int {} public void SetColor(Argb a) { .... 编译器很高兴让我定义它,并成功地构建了代码 现在我显然不能用传统意义上的,因为代码 var mySadCompiler = MyConfusingEnum; 没有指定值,但有趣的是,我能说 var myRoundTheHousesZeroState =

我今天意外地定义了一个不包含任何值的枚举。比如这个:

public enum MyConfusingEnum{}
public enum Argb : int {}

public void SetColor(Argb a) { ....
编译器很高兴让我定义它,并成功地构建了代码

现在我显然不能用传统意义上的,因为代码

var mySadCompiler = MyConfusingEnum;
没有指定值,但有趣的是,我能说

var myRoundTheHousesZeroState = Activator.CreateInstance<MyConfusingEnum>();
var myRoundTheHousesZeroState=Activator.CreateInstance();
正如我所提到的,它是值为0的
myconfusingeneum
的值类型


我的问题是,为什么编译器允许空定义,并且有任何可能有用的场景吗?

您可以将基础整数类型的任何值(我认为默认情况下
int
)强制转换为枚举-因此
(myconfusingeneum)42
现在将属于该枚举类型

总的来说,我不认为这是个好主意,但在某些情况下,“enum”值可能来自外部源代码,而使用
enum
时代码看起来更好

示例(假设代码包含枚举中的某些“基于int的状态”:

规范确实允许空枚举:

14.1枚举声明

枚举声明声明新的枚举类型。枚举声明以关键字enum开头,并定义枚举的名称、可访问性、基础类型和成员


请注意,
enum成员声明(opt)
被显式标记为variant,其中
{}
Activator.CreateInstance();
new MyConfusingEnum()相同()

调用枚举的构造函数将
0
作为值

由于设计决策,枚举可以具有对支持类型有效的任何值(通常为
int
),它不必是枚举中定义的值

出于该设计决策的原因,我可以向您指出一个题为“为什么将int强制转换为无效枚举值不会引发异常”的问题


@AlexeiLevenkov提供了允许空枚举的规范,我们可以猜测其基本原理是,由于任何支持类型值都是有效的,因此允许使用空枚举。

首先,您可以更轻松地完成以下操作:

MyConfusingEnum x1 = 0;
MyConfusingEnum x2 = default(MyConfusingEnum);
MyConfusingEnum x3 = new MyConfusingEnum();
MyConfusingEnum x4 = (MyConfusingEnum) 123;
以上所有工作都很好。(您可能会惊讶于第一个工作正常;有关详细信息,请参阅隐式枚举转换的规范部分。)

我的问题是为什么编译器允许空定义

我先用一个问题来回答你的问题。你会让编译器拒绝吗

class C {}
interface I {}
struct S {}
为什么

更直接地不回答您的问题:“为什么世界与现在没有什么不同?”这些问题很难回答。与其回答这个不可能的问题,我将回答这样一个问题:“假设将空枚举作为一个错误提交给设计团队;您会如何回应?”这个问题仍然是反事实的,但至少我能回答

接下来的问题是,该功能的成本是否以其优点为依据

为了工作,必须考虑、设计、指定、实施、测试、记录语言特性,并将其发送给客户。这是一种“产生错误”因此,错误信息必须被编写并翻译成十几种语言,文档也必须如此。实现该功能所需的五分钟时间将转化为许多人的工作时间,而这些人的工资相当高

然而,这实际上不是相关成本。机会成本是相关成本。预算是有限的,功能不是免费的,因此实施的任何功能都意味着必须削减一些其他功能;您希望削减哪个C#功能以获得此功能?因为不是一个能够做得更好的功能是机会成本

我还注意到,您提出的功能对任何人都没有明显的好处,这将使它很难被设计委员会接受。也许有一个我没有看到的引人注目的好处;如果是,它是什么

是否存在任何可能有用的场景

没有人会想到,“拒绝显然没有用处的程序”不是C#的设计目标

是否存在任何可能有用的场景

正如其他人已经提到的,您可以通过简单的强制转换将基础类型允许的任何值分配给该枚举。 这样,在int会使事情变得混乱的情况下,您可以强制执行类型检查。例如:

public enum MyConfusingEnum{}
public enum Argb : int {}

public void SetColor(Argb a) { ....
或者,您希望有一些扩展方法,而不包含int数据类型

public static Color GetColor(this Argb value) {
    return new Color( (int)value );
}

public static void Deconstruct( this Argb color, out byte alpha, out byte red, out byte green, out byte blue ) {
        alpha = (byte)( (uint)color >> 24 );
        red = (byte)( (uint)color >> 16 );
        green = (byte)( (uint)color >> 8 );
        blue = (byte)color;
}
并将其用作

var (alpha, red, green, blue) = color;
是否存在任何可能有用的场景

我在Java世界经历过一次

对于枚举

然而,在编译之前的某段时间,您可能还不知道所有的值,或者根本不打算实现任何值


在设计API的过程中,我实现了一个没有任何值的枚举,以便能够从其他接口引用它。我后来添加了值。

我确信答案是“因为规范定义了该行为”当然,下一个合乎逻辑的问题是……委员会为什么决定这样做……我认为你可以做
var x=(myconfusingeneum)0;
@ja72-你确实可以。每天都是上学日,嗯?你可以做
var x=(myconfusingeneum)有些不直观99
尽管如此。在处理VB.NET时,这会产生一个错误,我想说,不能声明一个空枚举有点烦人(因为我还没有查找值).请注意:谈论空接口-->标记interface@SilviuBurcea:Microsoft建议使用属性,而不是标记间隔。请参阅,VB.NET不允许您声明空枚举!!回答不错。tl