Java-Style-Enums in C#
Neulich bin ich über Java-Enums gestolpert.
Etwas erstaunt war ich, dass diese nicht äquivalent zu c# oder c++ sind, sondern im Gegenteil dazu noch viel mehr können! Dann kam die Frage auf, wie können wir uns dieses Konzept in C# zunutze machen?
Hier das Ergebnis:
Mit diesem Snippet (unten) kann ein Enum im Style von Java angelegt werden.
Angeregt wurde diese Idee unter anderem durch folgenden Post:
Java Enum - Oracle
Entweder kann der untere Code in ein Snippet-Editor für C# in Visual Studio eingefügt werden
oder einfach das Snippet unten aus dem Dateianhang herunterladen und die Dateiendung in ".snippet" umändern.
Ich denke hier ist es auch legitim Extension-Methods zu verwenden, um Java möglichst nahe zu kommen. Sie sollten im Idealfall andere Objekte nie stören, da Enums so gesehen keine Funktionen haben.
Bei Oracle gab es dazu folgendes Beispiel:
C#-Code: |
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);
private final double mass;
private final double radius;
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
private double mass() { return mass; }
private double radius() { return radius; }
public static final double G = 6.67300E-11;
double surfaceGravity() {
return G * mass / (radius * radius);
}
double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("Usage: java Planet <earth_weight>");
System.exit(-1);
}
double earthWeight = Double.parseDouble(args[0]);
double mass = earthWeight/EARTH.surfaceGravity();
for (Planet p : Planet.values())
System.out.printf("Your weight on %s is %f%n",
p, p.surfaceWeight(mass));
}
}
|
Hier also das Snippet und unten noch ein Beispiel dazu, wie man einen Java-Style-Enum daraus erstellen kann und dieses benutzt.
C#-Code: |
public enum $Testenum$
{
}
public static class $Testenum$Extensions
{
private static readonly IDictionary<$Testenum$, $Testenum$Data> _map;
static $Testenum$Extensions()
{
_map = new Dictionary<$Testenum$, $Testenum$Data>() {
};
}
public static $Testenum$Data Get$Testenum$Data(this $Testenum$ _value)
{
if (!_map.ContainsKey(_value))
throw new ArgumentOutOfRangeException("_map", "Unknown $Testenum$");
return _map[_value];
}
}
public class $Testenum$Data
{
public $Testenum$Data()
{
}
}
|
Hier also der Java-Style-Enum. Ich hab mit Absicht nicht die Planeten-Klasse genommen,
denn ich hoffe es probiert jemand mal aus. Sondern hier was gemacht, um z.B. in einem Abwasch Farben so als Int-Werte ausgeben zu können und ja ich bin mir bewusst, dass es in diesem Falle auch anders geht. :-)
C#-Code: |
public enum Colorable
{
Red,
Green,
Blue
}
public static class ColorableExtensions
{
private static readonly IDictionary<Colorable, ColorableData> _map;
static ColorableExtensions()
{
_map = new Dictionary<Colorable, ColorableData>()
{
{Colorable.Red, new ColorableData(Color.Red)},
{Colorable.Blue, new ColorableData(Color.Blue)},
{Colorable.Green, new ColorableData(Color.Green)}
};
}
public static ColorableData GetColorableData(this Colorable _value)
{
if (!_map.ContainsKey(_value))
throw new ArgumentOutOfRangeException("_map", "Unknown Colorable");
return _map[_value];
}
public static int RGBValue(this Colorable Colorable)
{
return GetColorableData(Colorable).RGBValue;
}
}
public class ColorableData
{
private readonly Color m_Color;
public ColorableData(Color _color)
{
m_Color = _color;
}
public int RGBValue { get { return m_Color.ToArgb(); } }
}
|
und zu guter letzt noch ein Beispiel für die Ausgabe:
C#-Code: |
foreach (Colorable color in typeof(Colorable).GetEnumValues())
{
MessageBox.Show(color.RGBValue().ToString());
}
|
Java Enum