C# VS Java Enum (For Those New to C#)

C# vs Java Enum (for those new to C#)

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

What's the equivalent of Java's enum in C#?

Full Java enum functionality isn't available in C#. You can come reasonably close using nested types and a private constructor though. For example:

using System;
using System.Collections.Generic;
using System.Xml.Linq;

public abstract class Operator
{
public static readonly Operator Plus = new PlusOperator();
public static readonly Operator Minus =
new GenericOperator((x, y) => x - y);
public static readonly Operator Times =
new GenericOperator((x, y) => x * y);
public static readonly Operator Divide =
new GenericOperator((x, y) => x / y);

// Prevent other top-level types from instantiating
private Operator()
{
}

public abstract int Execute(int left, int right);

private class PlusOperator : Operator
{
public override int Execute(int left, int right)
{
return left + right;
}
}

private class GenericOperator : Operator
{
private readonly Func<int, int, int> op;

internal GenericOperator(Func<int, int, int> op)
{
this.op = op;
}

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

Of course you don't have to use nested types, but they give the handy "custom behaviour" part which Java enums are nice for. In other cases you can just pass arguments to a private constructor to get a well-known restricted set of values.

A few things this doesn't give you:

  • Ordinal support
  • Switch support
  • EnumSet
  • Serialization/deserialization (as a singleton)

Some of that could probably be done with enough effort, though switch wouldn't really be feasible without hackery. Now if the language did something like this, it could do interesting things to make switch work by making the hackery automatic (e.g. declaring a load of const fields automatically, and changing any switch over the enum type to a switch over integers, only allowing "known" cases .)

Oh, and partial types mean you don't have to have all of the enum values in the same file. If each value got quite involved (which is definitely possible) each could have its own file.

Enums in Java VS Enums in C#

C# enums are very basic compared to Java enums. If you want to simulate the same kind of behavior you need to use a class with an inner enum:

using System.Collections.Generic;

public sealed class DayTime
{
public static readonly DayTime Morning = new DayTime("Morning", InnerEnum.Morning);
public static readonly DayTime Afternoon = new DayTime("Afternoon", InnerEnum.Afternoon);
public static readonly DayTime Night = new DayTime("Night", InnerEnum.Night);

private static readonly List<DayTime> valueList = new List<DayTime>();

static DayTime()
{
valueList.Add(Morning);
valueList.Add(Afternoon);
valueList.Add(Night);
}

//the inner enum needs to be public for use in 'switch' blocks:
public enum InnerEnum
{
Morning,
Afternoon,
Night
}

public readonly InnerEnum innerEnumValue;
private readonly string nameValue;
private readonly int ordinalValue;
private static int nextOrdinal = 0;

private string description;

internal DayTime(string name, InnerEnum innerEnum)
{
this.description = name;

nameValue = name;
ordinalValue = nextOrdinal++;
innerEnumValue = innerEnum;
}

public string Description
{
get
{
return description;
}
}

//the following methods reproduce Java built-in enum functionality:

public static DayTime[] values()
{
return valueList.ToArray();
}

public int ordinal()
{
return ordinalValue;
}

public override string ToString()
{
return nameValue;
}

public static DayTime valueOf(string name)
{
foreach (DayTime enumInstance in DayTime.valueList)
{
if (enumInstance.nameValue == name)
{
return enumInstance;
}
}
throw new System.ArgumentException(name);
}
}

Given this complexity, it may be best to rewrite your logic in a way that's more natural for C# without using enums.

Is it possible to mimic this java enum code in c#

Here's one option - not using enums, but something similar-ish...

public abstract class Logic
{
public static readonly Logic PayDay = new PayDayImpl();
public static readonly Logic CollectCash = new CollectCashImpl();
public static readonly Logic EtcEtc = new EtcEtcImpl();

// Prevent other classes from subclassing
private Logic() {}

public abstract void AcceptPlayer(Player player);

private class PayDayImpl : Logic
{
public override void AcceptPlayer(Player player)
{
// Perform logic
}
}

private class CollectCashImpl : Logic
{
public override void AcceptPlayer(Player player)
{
// Perform logic
}
}

private class EtcEtcImpl : Logic
{
public override void AcceptPlayer(Player player)
{
// Perform logic
}
}
}

You say that you don't want to provide a concrete class for each bit of logic - but that's basically what you'd be doing in Java anyway, it's just that the class would be slightly hidden from you.

Here's an alternative approach using delegates for the varying behaviour:

public sealed class Logic
{
public static readonly Logic PayDay = new Logic(PayDayAccept);
public static readonly Logic CollectCash = new Logic(CollectCashAccept);
public static readonly Logic EtcEtc = new Logic(player => {
// An alternative using lambdas...
});

private readonly Action<Player> accept;

private Logic(Action<Player> accept)
{
this.accept = accept;
}

public void AcceptPlayer(Player player)
{
accept(player);
}

private static void PayDayAccept(Player player)
{
// Logic here
}

private static void CollectCashAccept(Player player)
{
// Logic here
}
}

In both cases, you still get a fixed set of values - but you won't be able to switch on them. You could potentially have a separate "real" enum, but that would be a bit messy.

Enum in Java. Advantages?

You get free compile time checking of valid values. Using

public static int OPTION_ONE = 0;
public static int OPTION_TWO = 1;

does not ensure

void selectOption(int option) {
...
}

will only accept 0 or 1 as a parameter value. Using an enum, that is guaranteed. Moreover, this leads to more self documenting code, because you can use code completion to see all enum values.

Translate enum written in Java to C#

You could use a struct for this purpose, with a selected set of global singletons representing standard directions. I suggest a struct since your Direction object has value semantics:

public struct Direction : IEquatable<Direction>
{
short xstep;
short ystep;

public static Direction N { get { return new Direction(0, 1); } }
public static Direction E { get { return new Direction(1, 0); } }
public static Direction S { get { return new Direction(0, -1); } }
public static Direction W { get { return new Direction(-1, 0); } }

public static IEnumerable<Direction> Directions
{
get
{
yield return N;
yield return E;
yield return S;
yield return W;
}
}

Direction(int x, int y)
{
this.xstep = checked((short)x);
this.ystep = checked((short)y);
}

public int XStep { get { return xstep; } }

public int YStep { get { return ystep; } }

public Direction Left { get { return new Direction(-YStep, XStep); } }

public Direction Right { get { return new Direction(YStep, -XStep); } }

public override bool Equals(object obj)
{
if (obj is Direction)
{
var other = (Direction)obj;
return xstep == other.XStep && ystep == other.YStep;
}
return false;
}

public override int GetHashCode()
{
return (XStep.GetHashCode() | (YStep << 16).GetHashCode());
}

#region IEquatable<Direction> Members

public bool Equals(Direction other)
{
return this.xstep == other.xstep && this.ystep == other.ystep;
}

#endregion

public static Direction operator -(Direction direction)
{
return new Direction(-direction.XStep, -direction.YStep);
}

public static bool operator ==(Direction first, Direction second)
{
return first.Equals(second);
}

public static bool operator !=(Direction first, Direction second)
{
return !(first == second);
}

public override string ToString()
{
if (this == Direction.N)
return "N";
if (this == Direction.E)
return "E";
if (this == Direction.S)
return "S";
if (this == Direction.W)
return "W";
return string.Format("({0},{1}}", XStep.ToString(NumberFormatInfo.InvariantInfo), YStep.ToString(NumberFormatInfo.InvariantInfo));
}
}

The public static bool operator ==(Direction first, Direction second) allows directions to be compared simply using the == operator. This also requires overriding Equals and GetHashCode().

c# enums: can they take members and functions like java enums?

The only way to do something similar to this is to use extension methods, which can make it appear as though the enumeration has member methods.

Other than that, you could create a companion struct type to your enumeration that has a property for the enumeration value and then adds additional properties and methods to support that value.



Related Topics



Leave a reply



Submit