99

I know this rather goes against the idea of enums, but is it possible to extend enums in C#/Java? I mean "extend" in both the sense of adding new values to an enum, but also in the OO sense of inheriting from an existing enum.

I assume it's not possible in Java, as it only got them fairly recently (Java 5?). C# seems more forgiving of people that want to do crazy things, though, so I thought it might be possible some way. Presumably it could be hacked up via reflection (not that you'd every actually use that method)?

I'm not necessarily interested in implementing any given method, it just provoked my curiosity when it occurred to me :-)

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
alastairs
  • 6,697
  • 8
  • 50
  • 64
  • Does this answer your question? [Enum "Inheritance"](https://stackoverflow.com/questions/757684/enum-inheritance) – T.Todua Oct 30 '19 at 17:02

15 Answers15

113

The reason you can't extend Enums is because it would lead to problems with polymorphism.

Say you have an enum MyEnum with values A, B, and C , and extend it with value D as MyExtEnum.

Suppose a method expects a myEnum value somewhere, for instance as a parameter. It should be legal to supply a MyExtEnum value, because it's a subtype, but now what are you going to do when it turns out the value is D?

To eliminate this problem, extending enums is illegal

Rik
  • 28,507
  • 14
  • 48
  • 67
  • 5
    Actually, the reason is simply it doesn't make any sense. The problem you mention, ie client code receiving a constant it doesn't expect, still exists with the current implementation - in fact the compiler doesn't let you `switch` on enum values without either providing a `default` case or throwing an exception. And, even if it did, the enum at runtime could come from a separate compilation – Raffaele May 02 '14 at 10:37
  • @Raffaele I just tried this, and at least in Java 7, you can switch on an enum without a `default` case or throwing. – Dathan May 06 '14 at 17:38
  • @Dathan you are definitely right! As it's written, that is simply wrong - maybe I should remove it? I was thinking of the case when you use a `switch` to provide a required value, such as the initial of a local, or to `return` – Raffaele May 06 '14 at 18:18
  • 4
    This isn't personal, Rik. But this is pretty much the worst reason ever! Polymorphism and enum ... `DayOfWeek a = (DayOfWeek) 1; DayOfWeek b = (DayOfWeek) 4711; Console.WriteLine(a + ", " + b);` – Bitterblue Apr 15 '15 at 12:16
49

You're going the wrong way: a subclass of an enum would have fewer entries.

In pseudocode, think:

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

Any method that can accept an Animal should be able to accept a Mammal, but not the other way around. Subclassing is for making something more specific, not more general. That's why "object" is the root of the class hierarchy. Likewise, if enums were inheritable, then a hypothetical root of the enum hierarchy would have every possible symbol.

But no, C#/Java don't allow sub-enums, AFAICT, though it would be really useful at times. It's probably because they chose to implement Enums as ints (like C) instead of interned symbols (like Lisp). (Above, what does (Animal)1 represent, and what does (Mammal)1 represent, and are they the same value?)

You could write your own enum-like class (with a different name) that provided this, though. With C# attributes it might even look kind of nice.

Ken
  • 515
  • 4
  • 2
  • 4
    interesting analysis. never thought of it this way! – Abbas Gadhia Nov 11 '12 at 16:59
  • 1
    Intersting, but I think it is wrong. To imply there should be less types in a subclass makes sense in terms of animal classification trees, but not in terms of code. When you sublcass in code, there are never fewer methods. There are never fewer member variables. Your argument does not seem to apply to software as it does to animal classifications. – Kieveli Mar 11 '13 at 13:48
  • 6
    @Kieveli, your analysis is wrong. Adding a member does not have the same effect on an object as adding to the set of its possible values. This is not something Ken made up; there are clear and precise rules of computer science which explain why it works this way. Try searching for covariance and contravariance (not just academic masturbation either, it will help you understand rules for things like function signatures and containers). – jwg Mar 27 '13 at 17:04
  • @Kieveli Suppose you had a 'StreamWriter' class(takes stream - writes stream). You would create 'TextWriter : StreamWriter' (takes stream - writes text). Now you create 'HtmlWriter : TextWriter' (takes stream - writes pretty html). Now the HtmlWriter obviously does have more members, methods et cetera. Now try taking a stream from a sound card and writing it to file using HtmlWriter :) – evictednoise Sep 07 '16 at 10:30
  • This example is contrived, and doesn't prove that there should never be MORE enum values in the extended class. enum VehicalParts {License, Speed, Capacity}; enum CarParts{SteeringWheel, Winshield}; +everything that Vehical has too – Bernoulli Lizard Feb 28 '20 at 19:21
46

When built-in enums aren't enough, you can do it the old fashion way and craft your own. For example, if you wanted to add an additional property, for example, a description field, you could do it as follows:

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");
}

You can then treat it like an enum like so:

public void ProcessAction(Action a) {
    Console.WriteLine("Performing action: " + a.Name)
    if (a == Action.DoIt) {
       // ... and so on
    }
}

The trick is to make sure that the constructor is private (or protected if you want to inherit), and that your instances are static.

tsimon
  • 8,362
  • 2
  • 30
  • 41
  • I'm not a C# person, but don't you want a bit of final (or sealed/const/whatever) in there? – Tom Hawtin - tackline Sep 11 '08 at 12:29
  • 1
    I don't believe so. Or, at least, not for the situation where you'd be wanting to inherit from this class to add new "enum" values. Final and sealed prevent inheritance IIRC. – alastairs Sep 11 '08 at 19:50
  • 4
    @alastairs I think he meant adding `final` to the `public static Action DoIt = new Action("Do it", "This does things");` line, rather than the class. – crush Aug 13 '14 at 19:09
  • 1
    As in by adding `readonly`, ala: `public static readonly Action DoIt = new Action("Do it", "This does things");` – ErikE Jul 20 '15 at 20:43
15

Enums are supposed to represent the enumeration of all possible values, so extending rather does go against the idea.

However, what you can do in Java (and presumably C++0x) is have an interface instead of a enum class. Then put you standard values in an enum that implements the feature. Obviously you don't get to use java.util.EnumSet and the like. This is the approach taken in "more NIO features", which should be in JDK7.

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


public enum WTFResults implements Result {
    FILE_NOT_FOUND
}
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
4

You can use .NET reflection to retrieve the labels and values from an existing enum at run-time (Enum.GetNames() and Enum.GetValues() are the two specific methods you would use) and then use code injection to create a new one with those elements plus some new ones. This seems somewhat analagous to "inheriting from an existing enum".

McKenzieG1
  • 13,960
  • 7
  • 36
  • 42
3

I didn't see anyone else mention this but the ordinal value of an enum is important. For example, with grails when you save an enum to the database it uses the ordinal value. If you could somehow extend an enum, what would be the ordinal values of your extensions? If you extended it in multiple places how could you preserve some kind of order to these ordinals? Chaos/instability in the ordinal values would be a bad thing which is probably another reason why the language designers have not touched this.

Another difficulty if you were the language designer, how can you preserve the functionality of the values() method which is supposed to return all of the enum values. What would you invoke this on and how would it gather up all of the values?

2

Adding enums is a fairly common thing to do if you go back to the source code and edit, any other way (inheritance or reflection, if either is possible) is likely to come back and hit you when you get an upgrade of the library and they have introduced the same enum name or the same enum value - I have seen plenty of lowlevel code where the integer number matches to the binary encoding, where you would run into problems

Ideally code referencing enums should be written as equals only (or switches), and try to be future proof by not expecting the enum set to be const

Oskar
  • 2,234
  • 5
  • 28
  • 35
2

If you mean extends in the Base class sense, then in Java... no.

But you can extend an enum value to have properties and methods if that's what you mean.

For example, the following uses a Bracket enum:

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;
    }        
}
Allain Lalonde
  • 91,574
  • 70
  • 187
  • 238
1

I would like to be able to add values to C# enumerations which are combinations of existing values. For example (this is what I want to do):

AnchorStyles is defined as

public enum AnchorStyles { None = 0, Top = 1, Bottom = 2, Left = 4, Right = 8, }

and I would like to add an AnchorStyles.BottomRight = Right + Bottom so instead of saying

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

I can just say

my_ctrl.Anchor = AnchorStyles.BottomRight;

This doesn't cause any of the problems that have been mentioned above, so it would be nice if it was possible.

Magnum
  • 11
  • 2
  • You can so long as you can modify AnchorStyles: ```[Flags]public enum AnchorStyles { None = 0, Top = 1, Bottom = 2, Left = 4, Right = 8, BottomRight = 10 } ``` – thinkOfaNumber Jul 06 '23 at 06:47
1

Saw a post regarding this for Java a while back, check out http://www.javaspecialists.eu/archive/Issue161.html .

jwiklund
  • 2,058
  • 2
  • 15
  • 10
1

A temporary/local workaround, when you just want very local/one time usage:

enum Animals { Dog, Cat }
enum AnimalsExt { Dog = Animals.Dog, Cat= Animals.Cat,  MyOther}
// BUT CAST THEM when using:
var xyz = AnimalsExt.Cat;
MethodThatNeedsAnimal(   (Animals)xyz   );

See all answers at: Enum "Inheritance"

T.Todua
  • 53,146
  • 19
  • 236
  • 237
0

As far as java is concerned it is not allowed because adding elements to an enum would effectively create a super class rather than a sub class.

Consider:

 enum Person (JOHN SAM}   
 enum Student extends Person {HARVEY ROSS}

A general use case of Polymorphism would be

 Person person = Student.ROSS;   //not legal

which is clearly wrong.

T.Todua
  • 53,146
  • 19
  • 236
  • 237
Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
0

Some time back even i wanted to do something like this and found that enum extensions would voilate lot of basic concepts... (Not just polymorphisim)

But still u might need to do if the enum is declared in external library and Remember you should make a special caution when using this enum extensions...

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

You can't inherit from/extend an enum, you can use attributes to declare a description. If you're looking for an integer value, that's built-in.

bdukes
  • 152,002
  • 23
  • 148
  • 175
0

Hmmm - as far as I know, this can't be done - enumerations are written at design-time and are used as a convenience to the programmer.

I'm pretty sure that when the code is compiled, the equivalent values will be substituted for the names in your enumeration, thereby removing the concept of an enumeration and (therefore) the ability to extend it.

Chris Roberts
  • 18,622
  • 12
  • 60
  • 67