1

I'm new to C# but I've done a lot of programming in Java. In Java, you can create an enumerated object type (a class with only a fixed number of possible values) by declaring an enum with multiple fields and a private constructor. For example, this Java tutorial shows how to create an enumerated "Planet" type, which is an object (it has multiple fields of data) but has a fixed number of values (there are only 8 planets, so only 8 instances of this object ever exist).

However, it doesn't seem like there's any way to do this in C#, because enums in C# are only allowed to be primitive types, specifically numeric primitive types. Is there any simple way to force a C# object type to have a fixed number of possible instance values? Or should I just resort to some kind of Singleton Pattern/Factory Pattern architecture, such as giving the class a private constructor and defining a fixed number of static methods that return one of the valid instances?

Edward
  • 5,942
  • 4
  • 38
  • 55
  • Enumerations in C# can have string values as well. Also I think you'll have to go with your own architectural suggestion. – Geeky Guy Jun 28 '13 at 19:09
  • 2
    possible duplicate of [C# vs Java Enum (for those new to C#)](http://stackoverflow.com/questions/469287/c-sharp-vs-java-enum-for-those-new-to-c) I think this uses the exact example – mistahenry Jun 28 '13 at 19:10
  • 1
    Agreed on the duplicate. I would like to point out though, this implementation of Enum, and its complexity, IS a class. Its not an enum by the terms I am used to (anything in C). Given that I learned C first, I definitely would have used class or struct to define a planet rather than Enum anyway. – Nevyn Jun 28 '13 at 19:20
  • Wow, I can't believe I didn't find that question when I was searching for this. Feel free to mark as a duplicate. – Edward Jun 28 '13 at 19:40

3 Answers3

1

System.Drawing.Color is an example of this kind of thing.

The Color type has a collection of static properties of type Color that provide access to named colors. For example, System.Drawing.Color.CornflowerBlue.

The Color type allows you to create a Color without using the named color static members. If you want to prohibit this, you can make your class have only private constructors. Then the only way to get access to an instance of your type is to choose one of the available static properties of your type.

Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
0

You could create a static class that has static properties which represent your values. This is probably about as close as it gets.

public static class Planets
{
    // static cctor
    static Planets()
    {
        Saturn = new SaturnPlanet();
        Earth = new EarthPlanet();
        ...
    }

    public static Planet Saturn { get; private set; }
    public static Planet Earth { get; private set; }
    ...
}

You could choose to expose enumerators or IEnumerable methods or properties here as well.

For the sake of sanity, your Planets class and thus all of its property objects (in this case the Planet type) should be immutable. Otherwise you might end up with some nasty multi-threaded race conditions.

Haney
  • 32,775
  • 8
  • 59
  • 68
  • 1
    Wait, where do the `SaturnPlanet` and `EarthPlanet` classes come from? Are you saying I should define a subtype for each possible instance value of the enumerated type? – Edward Jun 28 '13 at 19:42
  • You don't have to, but it's just an example. I was assuming `SaturnPlanet : Planet` and `EarthPlanet : Planet` - you could just as easily simply have a single `Planet` class. – Haney Jun 28 '13 at 19:53
0

Enums inherit from System.Enum and are sealed (you can't inherit from an enum). Further enums are syntactic sugar on top of integral types (short, int, long, etc.). You could do something like this:

public enum Planet
{
    Mercury = 1 ,
    Venus   = 2 ,
    Earth   = 3 ,
    Mars    = 4 ,
    Jupiter = 5 ,
    Saturn  = 6 ,
    Uranus  = 7 ,
    Neptune = 8 ,
}
public interface IPlanetData
{
    double Mass   { get ; }
    double Radius { get ; }
}

public static class PlanetEnumHelpers
{
    private class PlanetData : IPlanetData
    {
        internal PlanetData( double mass , double radius )
        {
            Mass = mass ;
            Radius = radius ;
        }
        public double Mass   { get ; private set ; }
        public double Radius { get ; private set ; }
    }
    public static IPlanetData Data( this Planet planet )
    {
        IPlanetData instance ;

        switch ( planet )
        {
            case Planet.Mercury : instance = Mercury ; break ;
            case Planet.Venus   : instance = Venus   ; break ;
            case Planet.Earth   : instance = Earth   ; break ;
            case Planet.Mars    : instance = Mars    ; break ;
            case Planet.Jupiter : instance = Jupiter ; break ;
            case Planet.Saturn  : instance = Saturn  ; break ;
            case Planet.Uranus  : instance = Uranus  ; break ;
            case Planet.Neptune : instance = Neptune ; break ;
            default : throw new ArgumentOutOfRangeException("planet") ;
        }
        return instance ;
    }
    private static IPlanetData Mercury = new PlanetData( 3.303e+23 , 2.4397e6  ) ;
    private static IPlanetData Venus   = new PlanetData( 4.869e+24 , 6.0518e6  ) ;
    private static IPlanetData Earth   = new PlanetData( 5.976e+24 , 6.37814e6 ) ;
    private static IPlanetData Mars    = new PlanetData( 6.421e+23 , 3.3972e6  ) ;
    private static IPlanetData Jupiter = new PlanetData( 1.9e+27   , 7.1492e7  ) ;
    private static IPlanetData Saturn  = new PlanetData( 5.688e+26 , 6.0268e7  ) ;
    private static IPlanetData Uranus  = new PlanetData( 8.686e+25 , 2.5559e7  ) ;
    private static IPlanetData Neptune = new PlanetData( 1.024e+26 , 2.4746e7  ) ;
}
class Program
{
    static void Main( string[] args )
    {
        foreach ( Planet p in Enum.GetValues( typeof( Planet ) ) )
        {
            Console.WriteLine( "{0}: Mass={1} Radius={2}" , p , p.Data().Mass , p.Data().Radius );
        }
    }
}

which is a bit of a hack, but preserves the semantics of an Enum (e.g., ability to use it in a switch statement.

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135