为什么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