通过inheritance扩展一个枚举
我知道这反对枚举的想法,但是有可能在C#/ Java中扩展枚举吗? 我的意思是在给枚举增加新的值的意义上的“扩展”,也是在从现有枚举inheritance的OO意义上的“扩展”。
我认为在Java中是不可能的,因为它最近才得到它们(Java 5?)。 不过,C#似乎对那些想做疯狂事情的人更为宽容,所以我认为这可能是有可能的。 想必它可以通过reflection来破解(而不是你实际上都用这种方法)?
我不一定有兴趣实现任何给定的方法,它只是激起我的好奇心,当它发生在我身上:-)
你不能扩展枚举的原因是因为它会导致多态的问题。
假设你有一个枚举MyEnum,其值为A,B和C,并用值D扩展为MyExtEnum。
假设某个方法需要某个地方的myEnum值,例如作为一个参数。 提供一个MyExtEnum值应该是合法的,因为它是一个子types,但是现在当结果是D时,你会怎么做?
为了消除这个问题,扩展枚举是非法的
当内置的枚举不够时,你可以用老式的方式来创build你自己的。 例如,如果您想要添加其他属性(例如说明字段),则可以按如下所示进行操作:
public class Action { public string Name {get; private set;} public string Description {get; private set;} private Action(string name, string description) { Name = name; Description = description; } public static Action DoIt = new Action("Do it", "This does things"); public static Action StopIt = new Action("Stop It", "This stops things"); }
然后你可以把它像一个枚举像这样:
public void ProcessAction(Action a) { Console.WriteLine("Performing action: " + a.Name) if (a == Action.DoIt) { // ... and so on } }
诀窍是确保构造函数是私有的(或者如果要inheritance,则受到保护),并且您的实例是静态的。
你走错了方向:一个枚举的子类将有更less的条目。
在伪代码中,想想:
enum Animal { Mosquito, Dog, Cat }; enum Mammal : Animal { Dog, Cat }; // (not valid C#)
任何可以接受动物的方法都应该能够接受哺乳动物,而不是相反。 子类化是为了使一些更具体,而不是更一般化。 这就是为什么“对象”是类层次结构的根源。 同样,如果枚举是可inheritance的,那么枚举层次结构的假定根就会有每一个可能的符号。
但是,不,C#/ Java不允许子枚举,AFAICT,虽然它有时是非常有用的。 这可能是因为他们select将枚举实现为整数(如C)而不是实际的符号(如Lisp)。 (以上,(动物)1代表什么,(哺乳动物)1代表什么,它们是相同的值?)
尽pipe如此,你可以编写自己的枚举类(用不同的名字)。 有了C#属性,它甚至可能看起来不错。
枚举被认为是列举了所有可能的值,所以扩展而不符合这个想法。
然而,你可以在Java中(可能是C ++ 0x)做的是有一个接口,而不是一个枚举类。 然后把标准值放在一个实现了这个特性的枚举中。 显然你不会使用java.util.EnumSet之类的东西。 这是“更多的NIOfunction”所采取的方法,应该在JDK7中。
public interface Result { String name(); String toString(); } public enum StandardResults implements Result { TRUE, FALSE } public enum WTFResults implements Result { FILE_NOT_FOUND }
您可以使用.NETreflection从运行时检索现有枚举的标签和值( Enum.GetNames()
和Enum.GetValues()
是您将使用的两个特定的方法),然后使用代码注入来创build一个新的一个与这些元素加上一些新的。 这似乎有点类似于“从现有的枚举inheritance”。
添加枚举是一个相当常见的事情,如果你回到源代码和编辑,任何其他方式(inheritance或反思,如果可能的话)有可能会回来,打到你的图书馆和他们已经引入了相同的枚举名称或相同的枚举值 – 我已经看到了很多低级代码,整数与二进制编码匹配,在那里你会遇到问题
理想情况下,代码引用枚举应该写成只有等于(或开关),并试图通过不期望的枚举集是未来的certificate
我没有看到其他人提到这一点,但枚举的序数值是重要的。 例如,使用grails将枚举保存到数据库时,它使用序号值。 如果你能以某种方式扩展一个枚举,你的扩展的序数值是什么? 如果你在多个地方扩展它,你怎么能保留这些序号的某种秩序? 混乱/不稳定的顺序值将是一件坏事,这可能是语言devise师没有触及到的另一个原因。
如果你是语言devise者,另一个困难就是如何保留应该返回所有枚举值的values()方法的function。 你会怎样调用它,以及如何收集所有的价值?
如果你的意思是在基类的意义上扩展,那么在Java …号。
但是,如果这就是你的意思,你可以扩展一个枚举值来获得属性和方法。
例如,以下使用括号枚举:
class Person { enum Bracket { Low(0, 12000), Middle(12000, 60000), Upper(60000, 100000); private final int low; private final int high; Brackets(int low, int high) { this.low = low; this.high = high; } public int getLow() { return low; } public int getHigh() { return high; } public boolean isWithin(int value) { return value >= low && value <= high; } public String toString() { return "Bracket " + low + " to " + high; } } private Bracket bracket; private String name; public Person(String name, Bracket bracket) { this.bracket = bracket; this.name = name; } public String toString() { return name + " in " + bracket; } }
看了一个关于这个Java的post,回来,看看http://www.javaspecialists.eu/archive/Issue161.html 。
你不能inheritance/扩展一个枚举,你可以使用属性来声明一个描述 。 如果你正在寻找一个整数值,这是内置的。
嗯 – 据我所知,这是不可能的 – 枚举是在devise时写的,并作为方便程序员使用。
我非常肯定,当编译代码时,等价值将被replace为枚举中的名字,从而消除了枚举的概念,并且(因此)能够扩展它。
我希望能够将值添加到现有值的组合的C#枚举。 例如(这是我想要做的):
AnchorStyles被定义为
public enum AnchorStyles { None = 0, Top = 1, Bottom = 2, Left = 4, Right = 8, }
我想添加一个AnchorStyles.BottomRight = Right + Bottom,而不是说
my_ctrl.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
我可以说
my_ctrl.Anchor = AnchorStyles.BottomRight;
这不会导致上面提到的任何问题,所以如果可能的话,这将是很好的。
就Java而言,这是不允许的,因为添加元素到一个枚举将有效地创build一个超类而不是一个子类。
考虑:
enum Person (JOHN SAM} enum Student extends First {HARVEY ROSS}
多态性的一般用例是
Person person = Student.ROSS; //not legal
这显然是错误的。
有一段时间,即使我想要做这样的事情,发现枚举扩展会说很多的基本概念…(不只是polymorphisim)
但是,如果在外部库中声明了枚举,还是需要这样做,记住在使用这个枚举扩展时应该特别小心。
public enum MyEnum { A = 1, B = 2, C = 4 } public const MyEnum D = (MyEnum)(8); public const MyEnum E = (MyEnum)(16); func1{ MyEnum EnumValue = D; switch (EnumValue){ case D: break; case E: break; case MyEnum.A: break; case MyEnum.B: break; } }