C # vs Java Enum (für diejenigen, die neu in C # sind)

182

Ich habe eine Weile in Java programmiert und bin gerade auf ein Projekt gestoßen, das vollständig in C # geschrieben ist. Ich versuche, mich in C # auf den neuesten Stand zu bringen, und habe festgestellt, dass in meinem neuen Projekt an mehreren Stellen Aufzählungen verwendet werden. Auf den ersten Blick scheinen die Aufzählungen in C # jedoch einfacher zu sein als die Implementierung von Java 1.5+. Kann jemand die Unterschiede zwischen C # - und Java-Enums aufzählen und wie man die Unterschiede überwindet? (Ich möchte keinen Sprachflammenkrieg beginnen, ich möchte nur wissen, wie man einige Dinge in C # macht, die ich früher in Java gemacht habe). Könnte zum Beispiel jemand ein C # -Gleichstück zu Suns berühmtem Planet-Enum-Beispiel posten?

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 ...]
Oger Psalm33
quelle
1
@ycomp Ich kann das nicht gutschreiben. Es kommt von Sun (jetzt Oracle): docs.oracle.com/javase/tutorial/java/javaOO/enum.html
Ogre Psalm33

Antworten:

210

Aufzählungen in der CLR werden einfach als Konstanten bezeichnet. Der zugrunde liegende Typ muss ganzzahlig sein. In Java ähnelt eine Aufzählung eher einer benannten Instanz eines Typs. Dieser Typ kann sehr komplex sein und - wie Ihr Beispiel zeigt - mehrere Felder verschiedener Typen enthalten.

Um das Beispiel auf C # zu portieren, würde ich einfach die Aufzählung in eine unveränderliche Klasse ändern und statische schreibgeschützte Instanzen dieser Klasse verfügbar machen:

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;
    }
}
Kent Boogaart
quelle
4
Es ist diese Art von typsicherer Aufzählung, die wir armen Leute, die gezwungen sind, Java 1.4 und niedriger zu verwenden, implementieren müssen ... Die Aufzählungen von Java 5 sind möglicherweise die beste Funktion von Java 5+, insbesondere da sie in switch-Anweisungen verwendet werden können.
MetroidFan2002
9
@ Chris: Es sollten nur Flaggenaufzählungen pluralisiert werden. Das heißt, Aufzählungen, deren Mitglieder mit | kombiniert werden Operator.
Kent Boogaart
5
@Mladen: Das hängt ganz vom Kontext ab. Eine Aufzählung von Planeten kann perfekt für ein Spiel geeignet sein, das Zugriff auf eine begrenzte Anzahl von Planeten bietet. Änderungen am Code können genau das sein, was Sie wollen, wenn dem Spiel ein neuer Planet hinzugefügt wird.
Kent Boogaart
3
@Richie_W Sie können die Aufzählungen mit der Values-Eigenschaft durchlaufen.
Jonathan
23
Wow ... Es ist fast unglaublich zu sehen, dass etwas in C # ausführlicher implementiert ist als in Java
Sune Rasmussen
218

In C # können Sie definieren Erweiterungsmethoden für Aufzählungen Dies gleicht einige der fehlenden Funktionen aus.

Sie können Planetals Aufzählung definieren und haben auch Erweiterungsmethoden, die surfaceGravity()und entsprechensurfaceWeight() .

Ich habe benutzerdefinierte Attribute verwendet, wie von Mikhail vorgeschlagen , aber das gleiche könnte mit einem Wörterbuch erreicht werden.

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
}
finnw
quelle
20
Ich denke, das sollte mehr abgestimmt werden. Es ist näher an der Funktionsweise von Enums in Java. Ich kann so etwas wie Planet.MERCURY.GetSurfaceGravity () <machen. Beachten Sie die Erweiterungsmethode in einer Enum!
thenonhacker
2
Definitiv Ja. Erweiterungsmethoden für Enums (zum Teufel, Erweiterungsmethoden im Allgemeinen) sind eine großartige Ergänzung zu C #.
KeithS
3
@ AllGuralnek Danke. Nicht alle würden sich jedoch über Metadaten einig sein. Siehe MattDaveys Kommentar zu einer verwandten codereview.stackexchange-Frage .
Finnw
@finnw: Ich habe noch nie von der Code Review SE Seite gehört - danke dafür! Ich habe diese Diskussion dort fortgesetzt (obwohl sie hier bei Programmierern möglicherweise eine eigene Frage verdient).
Allon Guralnek
Dies ist eine großartige Lösung - hat jemand die Leistung getestet? Beispiel: Wie lange dauert der Zugriff auf das Attribut im Vergleich zum Zugriff auf eine Eigenschaft einer Klasse?
Simon Meyer
35

In C # können Attribute mit Aufzählungen verwendet werden. Ein gutes Beispiel für dieses Programmiermuster mit detaillierter Beschreibung finden Sie hier (Codeproject).

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

Bearbeiten: Diese Frage wurde kürzlich erneut gestellt und von Jon Skeet beantwortet: Was entspricht Javas Aufzählung in C #? Private innere Klassen in C # - warum werden sie nicht häufiger verwendet?

Bearbeiten 2: Sehen Sie die akzeptierte Antwort, die diesen Ansatz auf sehr brillante Weise erweitert!

Mikhail
quelle
1
Nett! Dies fühlt sich nur geringfügig klobig an, ist aber ansonsten eine sehr akzeptable Methode zum Hinzufügen zusätzlicher Daten zu einer Aufzählung. Ich bin ehrlich gesagt erstaunt, dass jemand so lange gebraucht hat, um diese großartige Lösung zu erwähnen!
Oger Psalm33
13

Java-Aufzählungen sind eigentlich vollständige Klassen, die einen privaten Konstruktor und Methoden usw. haben können, während C # -Aufzählungen nur als Ganzzahlen bezeichnet werden. Die Implementierung von IMO Java ist weit überlegen.

Diese Seite sollte Ihnen beim Lernen von c # aus einem Java-Camp sehr helfen. (Der Link verweist auf die Unterschiede bei den Aufzählungen (für andere Dinge nach oben / unten scrollen)

Richard Walton
quelle
1
Während Ihr Link einen interessanten, umfassenden Überblick über die Ähnlichkeiten und Unterschiede zwischen C # und Java bietet, enthält der Text viele Fehler (z. B. wird fälschlicherweise angegeben, dass Java geschützt gleich C # intern ist, während es intern geschützt sein sollte). Also nicht alles für selbstverständlich halten :)
Mafu
1
Ich würde nicht sagen, dass Java-Enums überlegen sind, selbst wenn ich ein Fan von Java bin. C # unterstützt eine einfache Ganzzahldeklaration, wie sie FOO = 0in ORM-Tools einfacher zu verwenden ist (keine fehleranfällige ordinal()Verwendung erforderlich). Weiteres C # unterstützt bitweise Aufzählungen, die oft sehr nützlich sind, insbesondere in Kombination mit EntityFramework. Java sollte ihre Aufzählungen erweitern, damit sie auch an Ganzzahlen gebunden werden können. Dann wären sie überlegen :)
djmj
4

So etwas denke ich:

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

Oder kombinieren Sie die Konstanten Planetwie oben in der Klasse

Chris S.
quelle
8
Nicht ganz - der Planet-Konstruktor sollte privat sein; Ein Teil des Punktes von Aufzählungen ist, dass sie eine feste Menge von Werten sind. Die Werte würden dann auch in der Planet-Klasse definiert.
Jon Skeet
Noch nicht. 1) Enumerator fehlt :) 2) Enums sollten niemals veränderbar sein. Oh und zuletzt bittet Ihr Code um eine einzelne Klasse (besonders wenn Sie einen privaten Konstruktor haben)
nawfal
3

Hier ist eine weitere interessante Idee, die das in Java verfügbare benutzerdefinierte Verhalten berücksichtigt. Ich habe mir folgende EnumerationBasisklasse ausgedacht:

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

Es hat im Grunde genommen einen Typparameter, damit die Ordnungszahl für verschiedene abgeleitete Aufzählungen ordnungsgemäß funktioniert. Das OperatorBeispiel von Jon Skeet aus seiner Antwort auf eine andere Frage (http://stackoverflow.com/questions/1376312/whats-the-equivalent-of-javas-enum-in-c) oben lautet dann:

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

Dies bietet einige Vorteile.

  • Ordentliche Unterstützung
  • Die Konvertierung in stringund intmacht switch-Anweisungen möglich
  • GetType () liefert für jeden Wert eines abgeleiteten Aufzählungstyps das gleiche Ergebnis.
  • Die statischen Methoden von System.Enumkönnen zur Basis-Enumerationsklasse hinzugefügt werden, um dieselbe Funktionalität zu ermöglichen.
Andrew Cooper
quelle
3

Wir haben gerade eine Enum-Erweiterung für c # erstellt https://github.com/simonmau/enum_ext erstellt

Es ist nur eine Implementierung für das Typensafeenum, aber es funktioniert großartig, also haben wir ein Paket zum Teilen erstellt - viel Spaß damit

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
quelle
2

Eine Java-Aufzählung ist syntaktischer Zucker, um Aufzählungen auf OO-Weise darzustellen. Es handelt sich um abstrakte Klassen, die die Enum-Klasse in Java erweitern, und jeder Enum-Wert ist wie eine statische endgültige öffentliche Instanzimplementierung der Enum-Klasse. Schauen Sie sich die generierten Klassen an und für eine Aufzählung "Foo" mit 10 Werten sehen Sie die generierten Klassen "Foo $ 1" bis "Foo $ 10".

Ich kenne C # jedoch nicht, ich kann nur spekulieren, dass eine Aufzählung in dieser Sprache eher einer traditionellen Aufzählung in Sprachen im C-Stil ähnelt. Ich sehe aus einer schnellen Google-Suche, dass sie jedoch mehrere Werte enthalten können, sodass sie wahrscheinlich auf ähnliche Weise implementiert werden, jedoch mit weitaus mehr Einschränkungen, als der Java-Compiler zulässt.

JeeBee
quelle
3
Geht es in Java und C # nicht nur um syntaktischen Zucker für JVM- oder CLR-Bytecodes? :) Sag einfach '
thenonhacker
2

Java-Enums ermöglichen einfache typsichere Konvertierungen aus dem Namen mithilfe der vom Compiler generierten valueOf-Methode, d. H.

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

Das Äquivalent für eine rohe Aufzählung in C # ist ausführlicher:

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

Wenn Sie jedoch den von Kent empfohlenen Weg gehen, können Sie problemlos eine ValueOfMethode in Ihrer Enum-Klasse implementieren .

serg10
quelle
Das Java-Beispiel verwendet eine vom Compiler generierte synthetische Methode - überhaupt nichts mit Generika zu tun. Enum hat eine generische valueOf-Methode, die jedoch die Generika von Class und nicht die von Enum verwendet.
Tom Hawtin - Tackline
2

Ich vermute, dass Enums in C # nur Konstanten innerhalb der CLR sind, aber nicht so vertraut mit ihnen. Ich habe einige Klassen in Java dekompiliert und kann Ihnen sagen, dass Enums einmal konvertiert werden sollen.

Java macht etwas hinterhältiges. Es behandelt die Aufzählungsklasse als eine normale Klasse, wobei, so nah ich es mir vorstellen kann, viele Makros verwendet werden, wenn auf die Aufzählungswerte verwiesen wird. Wenn Sie eine case-Anweisung in einer Java-Klasse haben, die Aufzählungen verwendet, werden die Aufzählungsreferenzen durch Ganzzahlen ersetzt. Wenn Sie zur Zeichenfolge wechseln müssen, wird ein Array von Zeichenfolgen erstellt, die durch eine Ordnungszahl indiziert sind, die in jeder Klasse verwendet wird. Ich vermute, beim Boxen zu sparen.

Wenn Sie diesen Dekompiler herunterladen, werden Sie sehen, wie er seine Klasse erstellt und integriert. Eher faszinierend um ehrlich zu sein. Früher habe ich die Enum-Klasse nicht verwendet, weil ich dachte, sie sei nur für eine Reihe von Konstanten aufgebläht. Mir gefällt es besser als die eingeschränkte Möglichkeit, sie in C # zu verwenden.

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

Paul Bruner
quelle
0

Die Aufzählung in Java ist viel komplexer als die C # -Aufzählung und daher leistungsfähiger. Da es sich nur um einen weiteren syntaktischen Zucker zur Kompilierungszeit handelt, frage ich mich, ob es sich wirklich gelohnt hat, die Sprache aufzunehmen, da sie in realen Anwendungen nur begrenzt verwendet wird. Manchmal ist es schwieriger, Dinge aus der Sprache herauszuhalten, als den Druck aufzugeben, ein kleines Feature aufzunehmen.

dmihailescu
quelle
2
Ich bin respektvoll anderer Meinung. Java 1.5-Enums sind eine leistungsstarke Sprachfunktion, die ich mehrfach verwendet habe, um eine OO-zentriertere Lösung für ein Problem zu implementieren, das sich mit diskreten Mengen von Elementen mit konstanten Namen befasst.
Oger Psalm33
1
Vielleicht hast du es getan. Über die intelligente Integration der Switch-Sprache hinaus kann der Rest der Funktionalität problemlos in C # oder Java selbst repliziert werden, wie die obigen Beispiele gezeigt haben.
Dmihailescu
@dmihailescu "Dann ist Enum in Java viel komplexer als C #. Also habe ich Java fallen gelassen ..."
Mukus
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
quelle
0

Sie können auch eine Dienstprogrammklasse für jeden Aufzählungstyp verwenden, die eine Instanz mit erweiterten Daten für jeden Aufzählungswert enthält.

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
quelle