206

I've been programming in Java for a while and just got thrown onto a project that's written entirely in C#. I'm trying to come up to speed in C#, and noticed enums used in several places in my new project, but at first glance, C#'s enums seem to be more simplistic than the Java 1.5+ implementation. Can anyone enumerate the differences between C# and Java enums, and how to overcome the differences? (I don't want to start a language flame war, I just want to know how to do some things in C# that I used to do in Java). For example, could someone post a C# counterpart to Sun's famous Planet enum example?

public enum Planet {
  MERCURY (3.303e+23, 2.4397e6),
  VENUS   (4.869e+24, 6.0518e6),
  EARTH   (5.976e+24, 6.37814e6),
  MARS    (6.421e+23, 3.3972e6),
  JUPITER (1.9e+27,   7.1492e7),
  SATURN  (5.688e+26, 6.0268e7),
  URANUS  (8.686e+25, 2.5559e7),
  NEPTUNE (1.024e+26, 2.4746e7),
  PLUTO   (1.27e+22,  1.137e6);

  private final double mass;   // in kilograms
  private final double radius; // in meters
  Planet(double mass, double radius) {
      this.mass = mass;
      this.radius = radius;
  }
  public double mass()   { return mass; }
  public double radius() { return radius; }

  // universal gravitational constant  (m3 kg-1 s-2)
  public static final double G = 6.67300E-11;

  public double surfaceGravity() {
      return G * mass / (radius * radius);
  }
  public double surfaceWeight(double otherMass) {
      return otherMass * surfaceGravity();
  }
}

// Example usage (slight modification of Sun's example):
public static void main(String[] args) {
    Planet pEarth = Planet.EARTH;
    double earthRadius = pEarth.radius(); // Just threw it in to show usage

    // Argument passed in is earth Weight.  Calculate weight on each planet:
    double earthWeight = Double.parseDouble(args[0]);
    double mass = earthWeight/pEarth.surfaceGravity();
    for (Planet p : Planet.values())
       System.out.printf("Your weight on %s is %f%n",
                         p, p.surfaceWeight(mass));
}

// Example output:
$ java Planet 175
Your weight on MERCURY is 66.107583
Your weight on VENUS is 158.374842
[etc ...]
Ogre Psalm33
  • 21,366
  • 16
  • 74
  • 92
  • 1
    @ycomp I can't take credit for that. It comes from Sun (now Oracle): http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html – Ogre Psalm33 Sep 22 '15 at 13:04

13 Answers13

244

In C# you can define extension methods on enums, and this makes up for some of the missing functionality.

You can define Planet as an enum and also have extension methods equivalent to surfaceGravity() and surfaceWeight().

I have used custom attributes as suggested by Mikhail, but the same could be achieved using a Dictionary.

using System;
using System.Reflection;

class PlanetAttr: Attribute
{
    internal PlanetAttr(double mass, double radius)
    {
        this.Mass = mass;
        this.Radius = radius;
    }
    public double Mass { get; private set; }
    public double Radius { get; private set; }
}

public static class Planets
{
    public static double GetSurfaceGravity(this Planet p)
    {
        PlanetAttr attr = GetAttr(p);
        return G * attr.Mass / (attr.Radius * attr.Radius);
    }

    public static double GetSurfaceWeight(this Planet p, double otherMass)
    {
        return otherMass * p.GetSurfaceGravity();
    }

    public const double G = 6.67300E-11;

    private static PlanetAttr GetAttr(Planet p)
    {
        return (PlanetAttr)Attribute.GetCustomAttribute(ForValue(p), typeof(PlanetAttr));
    }

    private static MemberInfo ForValue(Planet p)
    {
        return typeof(Planet).GetField(Enum.GetName(typeof(Planet), p));
    }

}

public enum Planet
{
    [PlanetAttr(3.303e+23, 2.4397e6)]  MERCURY,
    [PlanetAttr(4.869e+24, 6.0518e6)]  VENUS,
    [PlanetAttr(5.976e+24, 6.37814e6)] EARTH,
    [PlanetAttr(6.421e+23, 3.3972e6)]  MARS,
    [PlanetAttr(1.9e+27,   7.1492e7)]  JUPITER,
    [PlanetAttr(5.688e+26, 6.0268e7)]  SATURN,
    [PlanetAttr(8.686e+25, 2.5559e7)]  URANUS,
    [PlanetAttr(1.024e+26, 2.4746e7)]  NEPTUNE,
    [PlanetAttr(1.27e+22,  1.137e6)]   PLUTO
}
Community
  • 1
  • 1
finnw
  • 47,861
  • 24
  • 143
  • 221
  • 26
    I think this should be voted up more. It's closer to how enums in Java works. I can do something like Planet.MERCURY.GetSurfaceGravity() <-- Note the extension method on an Enum! –  May 25 '11 at 10:53
  • 4
    Definitely yes. Extension methods on Enums (heck, extension methods in general) are a great addition to C#. – KeithS Oct 18 '11 at 14:11
  • 4
    @AllonGuralnek Thanks. Not everybody would agree about metadata though. See MattDavey's comment on [a related codereview.stackexchange question](http://codereview.stackexchange.com/questions/5352/getting-the-value-of-a-custom-attribute-from-an-enum). – finnw Oct 21 '11 at 16:54
  • @finnw: I've never heard of the Code Review SE site - thanks for that! I've continues this discussion there (although it might deserve its own question here on Programmers). – Allon Guralnek Oct 21 '11 at 17:29
  • this is a great solution - has anyone tested the performance of this? e.g. how long does it take ta access the attribute, compared to accessing a property of a class. – Simon Meyer Feb 29 '16 at 13:22
  • @SimonMeyer Of course it is not practical to invoke Reflection - even if runtime-cached from a performance perspective. The answer is rate high because it correctly refers to __ENUM extension methods__, as the closest JAVA analog in C#. – Lorenz Lo Sauer Aug 24 '16 at 03:06
234

Enumerations in the CLR are simply named constants. The underlying type must be integral. In Java an enumeration is more like a named instance of a type. That type can be quite complex and - as your example shows - contain multiple fields of various types.

To port the example to C# I would just change the enum to an immutable class and expose static readonly instances of that class:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Planet planetEarth = Planet.MERCURY;

            double earthRadius = pEarth.Radius; // Just threw it in to show usage
            double earthWeight = double.Parse("123");
            double earthMass   = earthWeight / pEarth.SurfaceGravity();

            foreach (Planet p in Planet.Values)
                Console.WriteLine($"Your weight on {p} is {p.SurfaceWeight(mass)}");

            Console.ReadKey();
        }
    }

    public class Planet
    {
        public static readonly Planet MERCURY = new Planet("Mercury", 3.303e+23, 2.4397e6);
        public static readonly Planet VENUS   = new Planet("Venus", 4.869e+24, 6.0518e6);
        public static readonly Planet EARTH   = new Planet("Earth", 5.976e+24, 6.37814e6);
        public static readonly Planet MARS    = new Planet("Mars", 6.421e+23, 3.3972e6);
        public static readonly Planet JUPITER = new Planet("Jupiter", 1.9e+27, 7.1492e7);
        public static readonly Planet SATURN  = new Planet("Saturn", 5.688e+26, 6.0268e7);
        public static readonly Planet URANUS  = new Planet("Uranus", 8.686e+25, 2.5559e7);
        public static readonly Planet NEPTUNE = new Planet("Neptune", 1.024e+26, 2.4746e7);
        public static readonly Planet PLUTO   = new Planet("Pluto", 1.27e+22, 1.137e6);

        public static IEnumerable<Planet> Values
        {
            get
            {
                yield return MERCURY;
                yield return VENUS;
                yield return EARTH;
                yield return MARS;
                yield return JUPITER;
                yield return SATURN;
                yield return URANUS;
                yield return NEPTUNE;
                yield return PLUTO;
            }
        }

        public string Name   { get; private set; }
        public double Mass   { get; private set; }
        public double Radius { get; private set; }

        Planet(string name, double mass, double radius) => 
            (Name, Mass, Radius) = (name, mass, radius);

        // Wniversal gravitational constant  (m3 kg-1 s-2)
        public const double G = 6.67300E-11;
        public double SurfaceGravity()            => G * mass / (radius * radius);
        public double SurfaceWeight(double other) => other * SurfaceGravity();
        public override string ToString()         => name;
    }
}
AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
  • Doing that means you cannot use a for-each loop on the enums. – Richard Walton Jan 22 '09 at 14:30
  • 9
    It's this sort of type-safe enum that us poor people forced to use Java 1.4 and below have to implement...Java 5's enums are perhaps the best feature of Java 5+, especially since they can be used in switch statements. – MetroidFan2002 Jan 22 '09 at 14:45
  • 2
    Ok, of the answer's I've gotten so far, I like this one the best. This is along the lines I was thinking: if you want enum methods in C#, either change them to constants (as you did), or embed the enum inside a utility class (which might be harder to do with the "Planet" example). – Ogre Psalm33 Jan 22 '09 at 17:35
  • One very minor point is Microsoft suggest enum names being pluralized afaik – Chris S Jan 22 '09 at 20:50
  • 9
    @Chris: only flag enums should be pluralized. That is, enumerations whose members are combined using the | operator. – Kent Boogaart Apr 05 '09 at 09:10
  • 2
    I think the example is a silly one anyway. What if you wanted to add a new planet? You would have to edit the code. This is why you would use normal classes for the planets and not enums in Java or in C#. – Mladen Mihajlovic Apr 07 '09 at 11:34
  • 5
    @Mladen: It depends entirely on the context. An enumeration of planets may be perfectly suited to a game that provides access to a limited number of planets. Changes to the code may be precisely what you want if a new planet is added to the game. – Kent Boogaart Apr 07 '09 at 11:38
  • @Kent true, but it still doesn't sound like good design to me. If I wanted to create an expansion for a game (for example) I would want all this info to be decoupled from the original code. Still, not saying that there isn't a place for enums, just that the example does not fit them in my eyes. – Mladen Mihajlovic Apr 08 '09 at 08:52
  • 3
    @Richie_W you can iterate over the enums using the Values property. – Jonathan Dec 06 '10 at 15:57
  • @Richie_W he does have a sense of humor. "Alien Approach", get it? – Erix Dec 08 '11 at 22:47
  • 25
    Wow... It's almost unbelieveable to see something implemented in a more verbose way in C# than in Java – Sune Rasmussen Sep 25 '12 at 08:50
  • 1
    @KentBoogaart Isn't this perfect for a struct instead of class? – nawfal May 08 '13 at 13:37
  • 2
    I think it's better to use an array for the values instead of `public static IEnumerable Values`, something like `private static Plan[] values = {VIP, CHEAP, MEDIUM, D_PLAN};`. It will then be closer to the Java enum (you can have length and access each enum with an index) – Fr4nz Jul 10 '13 at 11:27
  • Using this example, if you wanted to convert the name of a planet as a string to a Planet object, how would you do it? I would want to be able to do something like `var p = "Earth"; var enum = (Planet)p;`. – user1636130 May 30 '16 at 15:48
  • 3
    @nawfal I thought so at first glance but unlike C#, java `enum` can be null. I think `class` is more equivalent in this point of view. – Attacktive Jul 26 '16 at 04:52
  • @Suzi, Furthermore, in the given type, it takes a double and a double and a reference which should add upto 20 bytes. Not good for struct type if it is more than 16 bytes as a rule of thumb, copying and all that. My initial comment was pretty dumb :) – nawfal Jul 26 '16 at 05:50
  • Can't use in a switch though :( – Sinaesthetic Aug 23 '16 at 00:07
  • This isn't available at compile time. I haven't found a way to use one of the Planets as a default value for a function parameter. :( – Zorgarath May 19 '17 at 19:38
40

In C# attributes can be used with enums. Good example of this programming pattern with detailed description is here (Codeproject)

public enum Planet
{
   [PlanetAttr(3.303e+23, 2.4397e6)]
   Mercury,
   [PlanetAttr(4.869e+24, 6.0518e6)]
   Venus
} 

Edit: this question has been recently asked again and answered by Jon Skeet: What's the equivalent of Java's enum in C#? Private inner classes in C# - why aren't they used more often?

Edit 2: see the accepted answer which extends this approach in a very brilliant way!

Community
  • 1
  • 1
Mikhail Poda
  • 5,742
  • 3
  • 39
  • 52
  • 1
    Nice! This feels only slightly clunky, but is otherwise a very acceptable method for adding extra data to an enum. I'm frankly amazed that it took someone this long to mention this great solution! – Ogre Psalm33 Sep 14 '09 at 19:11
13

Java enums are actually full classes which can have a private constructor and methods etc, whereas C# enums are just named integers. IMO Java's implementation is far superior.

This page should help you a lot while learning c# coming from a java camp. (The link points to the differences about enums (scroll up / down for other things)

Richard Walton
  • 4,789
  • 3
  • 38
  • 49
  • 1
    While your link gives an interesting, extensive overview of the similarities and differences between C# and Java, there are a lot of mistakes in the text (eg wrongly states that Java protected equals C# internal while it should be internal protected). So don't take everything there for granted :) – mafu Jan 23 '09 at 11:39
  • 1
    I would not say Java enums are superior even if i am a fan of java. C# supports easy integer declaration such as `FOO = 0` which is easier to use in ORM tools (no error prone `ordinal()` usage necessary). Further C# supports bitwise enumerations which are often very usefull, especially in combination with `EntityFramework`. Java should extend their enums to allow them to be binded to integers too. Then they would be superior :) – djmj Aug 29 '15 at 00:05
5

Something like this I think:

public class Planets 
{
    public static readonly Planet MERCURY = new Planet(3.303e+23, 2.4397e6);
    public static readonly Planet VENUS = new Planet(4.869e+24, 6.0518e6);
    public static readonly Planet EARTH = new Planet(5.976e+24, 6.37814e6);
    public static readonly Planet MARS = new Planet(6.421e+23, 3.3972e6);
    public static readonly Planet JUPITER = new Planet(1.9e+27,   7.1492e7);
    public static readonly Planet SATURN = new Planet(5.688e+26, 6.0268e7);
    public static readonly Planet URANUS = new Planet(8.686e+25, 2.5559e7);
    public static readonly Planet NEPTUNE = new Planet(1.024e+26, 2.4746e7);
    public static readonly Planet PLUTO = new Planet(1.27e+22,  1.137e6);
}

public class Planet
{
    public double Mass {get;private set;}
    public double Radius {get;private set;}

    Planet(double mass, double radius)
    {
        Mass = mass;
        Radius = radius;
    }

    // universal gravitational constant  (m3 kg-1 s-2)
    private static readonly double G = 6.67300E-11;

    public double SurfaceGravity()
    {
        return G * Mass / (Radius * Radius);
    }

    public double SurfaceWeight(double otherMass)
    {
        return otherMass * SurfaceGravity();
    }
}

Or combine the constants into the Planet class as above

Nissa
  • 4,636
  • 8
  • 29
  • 37
Chris S
  • 64,770
  • 52
  • 221
  • 239
  • 9
    Not quite - the Planet constructor should be private; part of the point of enums is that they're a fixed set of values. The values would then be defined in the Planet class too. – Jon Skeet Jan 22 '09 at 15:06
  • Not yet. 1) enumerator is missing :) 2) enums should never be mutable. Oh and last, your code begs for one single class (esp when you are having a private constructor) – nawfal May 08 '13 at 13:28
5

we have just made an enum extension for c# https://github.com/simonmau/enum_ext

It's just a implementation for the typesafeenum, but it works great so we made a package to share - have fun with it

public sealed class Weekday : TypeSafeNameEnum<Weekday, int>
{
    public static readonly Weekday Monday = new Weekday(1, "--Monday--");
    public static readonly Weekday Tuesday = new Weekday(2, "--Tuesday--");
    public static readonly Weekday Wednesday = new Weekday(3, "--Wednesday--");
    ....

    private Weekday(int id, string name) : base(id, name)
    {
    }
}
simonmau
  • 69
  • 1
  • 3
4

Here's another interesting idea which caters for the custom behaviour available in Java. I came up with the following Enumeration base class:

public abstract class Enumeration<T>
    where T : Enumeration<T>
{   
    protected static int nextOrdinal = 0;

    protected static readonly Dictionary<int, Enumeration<T>> byOrdinal = new Dictionary<int, Enumeration<T>>();
    protected static readonly Dictionary<string, Enumeration<T>> byName = new Dictionary<string, Enumeration<T>>();

    protected readonly string name;
    protected readonly int ordinal;

    protected Enumeration(string name)
        : this (name, nextOrdinal)
    {
    }

    protected Enumeration(string name, int ordinal)
    {
        this.name = name;
        this.ordinal = ordinal;
        nextOrdinal = ordinal + 1;
        byOrdinal.Add(ordinal, this);
        byName.Add(name, this);
    }

    public override string ToString()
    {
        return name;
    }

    public string Name 
    {
        get { return name; }
    }

    public static explicit operator int(Enumeration<T> obj)
    {
        return obj.ordinal;
    }

    public int Ordinal
    {
        get { return ordinal; }
    }
}

It's got a type parameter basically just so the ordinal count will work properly across different derived enumerations. Jon Skeet's Operator example from his answer to another question (http://stackoverflow.com/questions/1376312/whats-the-equivalent-of-javas-enum-in-c) above then becomes:

public class Operator : Enumeration<Operator>
{
    public static readonly Operator Plus = new Operator("Plus", (x, y) => x + y);
    public static readonly Operator Minus =  new Operator("Minus", (x, y) => x - y);
    public static readonly Operator Times =  new Operator("Times", (x, y) => x * y);
    public static readonly Operator Divide = new Operator("Divide", (x, y) => x / y);

    private readonly Func<int, int, int> op;

    // Prevent other top-level types from instantiating
    private Operator(string name, Func<int, int, int> op)
        :base (name)
    {
        this.op = op;
    }

    public int Execute(int left, int right)
    {
        return op(left, right);
    }
}

This gives a few advantages.

  • Ordinal support
  • Conversion to string and int which makes switch statements feasible
  • GetType() will give the same result for each of the values of a derived Enumeration type.
  • The Static methods from System.Enum can be added to the base Enumeration class to allow the same functionality.
Andrew Cooper
  • 32,176
  • 5
  • 81
  • 116
2

A Java enum is syntactic sugar to present enumerations in an OO manner. They're abstract classes extending the Enum class in Java, and each enum value is like a static final public instance implementation of the enum class. Look at the generated classes, and for an enum "Foo" with 10 values, you'll see "Foo$1" through "Foo$10" classes generated.

I don't know C# though, I can only speculate that an enum in that language is more like a traditional enum in C style languages. I see from a quick Google search that they can hold multiple values however, so they are probably implemented in a similar manner, but with far more restrictions than what the Java compiler allows.

JeeBee
  • 17,476
  • 5
  • 50
  • 60
  • 3
    Well isn't everything in Java and C# all about syntactic sugar for JVM or CLR bytecodes? :) Just sayin' –  May 25 '11 at 10:55
2

Java enums allow easy typesafe conversions from the name using the compiler-generated valueOf method, i.e.

// Java Enum has generics smarts and allows this
Planet p = Planet.valueOf("MERCURY");

The equivalent for a raw enum in C# is more verbose:

// C# enum - bit of hoop jumping required
Planet p = (Planet)Enum.Parse(typeof(Planet), "MERCURY");

However, if you go down the route sugegsted by Kent, you can easily implement a ValueOf method in your enum class.

serg10
  • 31,923
  • 16
  • 73
  • 94
  • The Java example is using a synthetic method generated by the compiler - nothing to do with generics at all. Enum does have a generic valueOf method, but that uses Class' generics and not Enum's. – Tom Hawtin - tackline Apr 05 '09 at 12:12
2

I suspect enums in C# are just constants internal to the CLR, but not that familiar with them. I have decompiled some classes in Java and I can tell you want Enums are once you convert.

Java does something sneaky. It treats the enum class as a a normal class with, as close as I can figure, using lots of macros when referencing the enum values. If you have a case statement in a Java class that uses enums, it replaces the enum references to integers. If you need to go to string, it creates an array of strings indexed by an ordinal that it uses in each class. I suspect to save on boxing.

If you download this decompiler you will get to see how it creates its class an integrates it. Rather fascinating to be honest. I used to not use the enum class because I thought it was to bloated for just an array of constants. I like it better than the limited way you can use them in C#.

http://members.fortunecity.com/neshkov/dj.html -- Java decompiler

Paul Bruner
  • 435
  • 4
  • 8
0
//Review the sample enum below for a template on how to implement a JavaEnum.
//There is also an EnumSet implementation below.

public abstract class JavaEnum : IComparable {
    public static IEnumerable<JavaEnum> Values {
        get {
            throw new NotImplementedException("Enumeration missing");
        }
    }

    public readonly string Name;

    public JavaEnum(string name) {
        this.Name = name;
    }

    public override string ToString() {
        return base.ToString() + "." + Name.ToUpper();
    }

    public int CompareTo(object obj) {
        if(obj is JavaEnum) {
            return string.Compare(this.Name, ((JavaEnum)obj).Name);
        } else {
            throw new ArgumentException();
        }
    }


    //Dictionary values are of type SortedSet<T>
    private static Dictionary<Type, object> enumDictionary;
    public static SortedSet<T> RetrieveEnumValues<T>() where T : JavaEnum {
        if(enumDictionary == null) {
            enumDictionary = new Dictionary<Type, object>();
        }
        object enums;
        if(!enumDictionary.TryGetValue(typeof(T), out enums)) {
            enums = new SortedSet<T>();
            FieldInfo[] myFieldInfo = typeof(T).GetFields(BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Public);
            foreach(FieldInfo f in myFieldInfo) {
                if(f.FieldType == typeof(T)) {
                    ((SortedSet<T>)enums).Add((T)f.GetValue(null));
                }
            }
            enumDictionary.Add(typeof(T), enums);
        }
        return (SortedSet<T>)enums;
    }
}


//Sample JavaEnum
public class SampleEnum : JavaEnum {
    //Enum values
    public static readonly SampleEnum A = new SampleEnum("A", 1);
    public static readonly SampleEnum B = new SampleEnum("B", 2);
    public static readonly SampleEnum C = new SampleEnum("C", 3);

    //Variables or Properties common to all enums of this type
    public int int1;
    public static int int2 = 4;
    public static readonly int int3 = 9;

    //The Values property must be replaced with a call to JavaEnum.generateEnumValues<MyEnumType>() to generate an IEnumerable set.
    public static new IEnumerable<SampleEnum> Values {
        get {
            foreach(var e in JavaEnum.RetrieveEnumValues<SampleEnum>()) {
                yield return e;
            }
            //If this enum should compose several enums, add them here
            //foreach(var e in ChildSampleEnum.Values) {
            //    yield return e;
            //}
        }
    }

    public SampleEnum(string name, int int1)
        : base(name) {
        this.int1 = int1;
    }
}


public class EnumSet<T> : SortedSet<T> where T : JavaEnum {
    // Creates an enum set containing all of the elements in the specified element type.
    public static EnumSet<T> AllOf(IEnumerable<T> values) {
        EnumSet<T> returnSet = new EnumSet<T>();
        foreach(T item in values) {
            returnSet.Add(item);
        }
        return returnSet;
    }

    // Creates an enum set with the same element type as the specified enum set, initially containing all the elements of this type that are not contained in the specified set.
    public static EnumSet<T> ComplementOf(IEnumerable<T> values, EnumSet<T> set) {
        EnumSet<T> returnSet = new EnumSet<T>();
        foreach(T item in values) {
            if(!set.Contains(item)) {
                returnSet.Add(item);
            }
        }
        return returnSet;
    }

    // Creates an enum set initially containing all of the elements in the range defined by the two specified endpoints.
    public static EnumSet<T> Range(IEnumerable<T> values, T from, T to) {
        EnumSet<T> returnSet = new EnumSet<T>();
        if(from == to) {
            returnSet.Add(from);
            return returnSet;
        }
        bool isFrom = false;
        foreach(T item in values) {
            if(isFrom) {
                returnSet.Add(item);
                if(item == to) {
                    return returnSet;
                }
            } else if(item == from) {
                isFrom = true;
                returnSet.Add(item);
            }
        }
        throw new ArgumentException();
    }

    // Creates an enum set initially containing the specified element(s).
    public static EnumSet<T> Of(params T[] setItems) {
        EnumSet<T> returnSet = new EnumSet<T>();
        foreach(T item in setItems) {
            returnSet.Add(item);
        }
        return returnSet;
    }

    // Creates an empty enum set with the specified element type.
    public static EnumSet<T> NoneOf() {
        return new EnumSet<T>();
    }

    // Returns a copy of the set passed in.
    public static EnumSet<T> CopyOf(EnumSet<T> set) {
        EnumSet<T> returnSet = new EnumSet<T>();
        returnSet.Add(set);
        return returnSet;
    }

    // Adds a set to an existing set.
    public void Add(EnumSet<T> enumSet) {
        foreach(T item in enumSet) {
            this.Add(item);
        }
    }

    // Removes a set from an existing set.
    public void Remove(EnumSet<T> enumSet) {
        foreach(T item in enumSet) {
            this.Remove(item);
        }
    }
}
Jim
  • 869
  • 1
  • 10
  • 16
0

You could also use a utility class for each enum type which holds a instance with advanced data for each enum value.

public enum Planet
{
    MERCURY,
    VENUS
}

public class PlanetUtil
{
    private static readonly IDictionary<Planet, PlanetUtil> PLANETS = new Dictionary<Planet, PlanetUtil();

    static PlanetUtil()
    {
        PlanetUtil.PLANETS.Add(Planet.MERCURY, new PlanetUtil(3.303e+23, 2.4397e6));
        PlanetUtil.PLANETS.Add(Planet.VENUS, new PlanetUtil(4.869e+24, 6.0518e6));
    }

    public static PlanetUtil GetUtil(Planet planet)
    {
        return PlanetUtil.PLANETS[planet];
    }

    private readonly double radius;
    private readonly double mass;

    public PlanetUtil(double radius, double mass)
    {
        this.radius = radius;
        this.mass = mass;
    }

    // getter
}
djmj
  • 5,579
  • 5
  • 54
  • 92
0

The enum in Java is much more complex than C# enum and hence more powerful. Since it is just another compile time syntactical sugar I'm wondering if it was really worth having included the language given its limited usage in real life applications. Sometimes it's harder keeping stuff out of the language than giving up to the pressure to include a minor feature.

  • 2
    I respectfully disagree. Java 1.5 enums are a powerful language feature that I have used numerous times to implement a more OO-centric solution to a problem dealing with discrete set of constant named items. – Ogre Psalm33 May 25 '11 at 13:39
  • 1
    May be you did. But beyond the smart 'switch' language integration, the rest of the functionality can be easily replicated in C# or Java itself as the above examples showed. – dmihailescu Jun 03 '11 at 21:12
  • @dmihailescu"Then enum in Java is much more complex than C#. So I dropped Java..." – Mukus Feb 12 '15 at 04:22