通过继承扩展枚举

时间:2020-03-05 18:51:06  来源:igfitidea点击:

我知道这有点违背枚举的概念,但是可以在C#/ Java中扩展枚举吗?我的意思是"扩展",既是向枚举添加新值,也就是从现有枚举继承的OO。

我认为这在Java中是不可能的,因为它只是最近才得到的(Java 5?)。不过,似乎更宽容的人想做疯狂的事情,所以我认为这可能是有可能的。大概可以通过反思来破解它(不是每个人都实际使用该方法)?

我不一定对实现任何给定的方法感兴趣,它只是在引起我好奇时才引起我的好奇:-)

解决方案

回答

我们不能继承/扩展枚举,可以使用属性来声明描述。如果我们正在寻找一个整数值,那是内置的。

回答

据我所知,这无法做到,枚举是在设计时编写的,并且为程序员提供了便利。

我非常确定,在编译代码时,将使用等效值替换枚举中的名称,从而消除了枚举的概念以及(因此)扩展了枚举的能力。

回答

如果我们返回源代码并进行编辑,则添加枚举是很常见的事情,当我们升级库并升级时,任何其他方式(继承或者反射,如果可能的话)都可能会回来并打击我们他们引入了相同的枚举名称或者相同的枚举值,我见过很多低级代码,其中整数与二进制编码匹配,我们会遇到问题

理想情况下,应将引用枚举的代码编写为仅等于(或者使用开关),并通过不期望枚举设置为const来尝试作为将来的证明。

回答

我们可以使用.NET反射在运行时从现有枚举中检索标签和值(" Enum.GetNames()"和" Enum.GetValues()"是我们要使用的两种特定方法),然后使用代码注入用这些元素和一些新元素创建一个新元素。这似乎有点类似于"从现有枚举继承"。

回答

我们无法扩展Enums的原因是,这将导致多态性问题。

假设我们有一个枚举MyEnum,其值分别为A,B和C,并将其值D扩展为MyExtEnum。

假设某个方法在某处期望myEnum值,例如作为参数。提供MyExtEnum值应该是合法的,因为它是子类型,但是现在当值变成D时我们将要做什么?

为了消除此问题,扩展枚举是非法的

回答

当内置枚举还不够时,我们可以按照旧的方式进行操作,然后自己制作。例如,如果要添加其他属性,例如描述字段,则可以按以下步骤进行操作:

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
    }
}

诀窍是确保构造函数是私有的(如果要继承则受保护),并且实例是静态的。

回答

如果意思是在基类的意义上扩展,那么在Java中……不。

但是,如果这就是意思,则可以扩展枚举值以具有属性和方法。

例如,以下代码使用Bracket枚举:

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(可能是C ++ 0x)中可以执行的是使用接口而不是枚举类。然后,将标准值放入实现该功能的枚举中。显然,我们不会使用java.util.EnumSet之类的东西。这是"更多NIO功能"中采用的方法,应该在JDK7中使用。

public interface Result {
    String name();
    String toString();
}
public enum StandardResults implements Result {
    TRUE, FALSE
}

public enum WTFResults implements Result {
    FILE_NOT_FOUND
}

回答

不久以前就看到了有关Java的帖子,请访问http://www.javaspecialists.eu/archive/Issue161.html。

回答

我们采用的方式是错误的:枚举的子类将具有较少的条目。

用伪代码考虑:

enum Animal { Mosquito, Dog, Cat };
enum Mammal : Animal { Dog, Cat };  // (not valid C#)

任何可以接受动物的方法都应该能够接受哺乳动物,但不能接受其他方法。子类化是为了使某些内容更具体而不是更笼统。这就是为什么"对象"是类层次结构的根源。同样,如果枚举是可继承的,则枚举层次结构的假想根将具有所有可能的符号。

但是不,C#/ Java不允许使用子枚举AFAICT,尽管有时它确实很有用。可能是因为他们选择将Enums实现为整数(如C)而不是内部符号(如Lisp)。 (以上,(动物)1代表什么,(哺乳动物)1代表什么,它们的值相同吗?)

不过,我们可以编写自己的提供类似枚举的类(使用不同的名称)。有了Cattributes,它甚至看起来还不错。

回答

我没有看到其他人提及此事,但枚举的序数值很重要。例如,对于grails,当我们将枚举保存到数据库时,它将使用序数值。如果我们可以通过某种方式扩展枚举,则扩展的序数值是什么?如果我们将其扩展到多个位置,我们如何保留这些普通订单的某种顺序?序数值中的混乱/不稳定性将是一件坏事,这可能是语言设计人员未曾涉及此问题的另一个原因。

如果我们是语言设计人员,则另一个困难是,如何保留values()方法的功能,该方法应该返回所有枚举值。我们将如何调用它,它将如何收集所有值?

回答

我希望能够将值添加到作为现有值组合的Cenumerations中。例如(这就是我想要做的):

AnchorStyles定义为

公共枚举AnchorStyles { 无= 0, 顶端= 1 底部= 2, 左= 4, 右= 8 }

我想添加一个AnchorStyles.BottomRight = Right + Bottom,所以不用说

my_ctrl.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;

我可以说

my_ctrl.Anchor = AnchorStyles.BottomRight;

这不会引起上面提到的任何问题,因此,如果可能的话,会很好。