Class Coin has the following properties: MoneyType, Value, Diameter.
MoneyType is enum:
enum CoinType
{
Cent,
Nickel,
Dime,
QuarterDollar,
HalfDollar,
Dollar,
}
Each MoneyType should have specific Value and Diameter, for example Cent: Value = 1 and Diameter = 19, so if I assign MoneyType, Value and Diameter should be assigned automatically according to MoneyType. Not sure how to do this. Maybe some kind of enum tuples?
For example:
enum CoinType
{
(Cent, 1, 19),
(Nickel, 10, 21),
.....
}
I just want that every MoneyType has specific Value and Diameter.
Another way you can do it is by implementing your custom enum.
Source is modified according to your needs.
#region Base Abstract Class
public abstract class EnumBaseType<T> where T : EnumBaseType<T>
{
protected static List<T> enumValues = new List<T>();
public readonly string Key;
public readonly int Value;
public readonly int Diameter;
public EnumBaseType(string key, int value, int diameter)
{
Key = key;
Value = value;
Diameter = diameter;
enumValues.Add((T)this);
}
protected static System.Collections.ObjectModel.ReadOnlyCollection<T> GetBaseValues()
{
return enumValues.AsReadOnly();
}
protected static T GetBaseByKey(string key)
{
foreach (T t in enumValues)
{
if (t.Key == key) return t;
}
return null;
}
}
#endregion
#region Enhanced Enum Sample
public class MoneyType : EnumBaseType<MoneyType>
{
public static readonly MoneyType Cent = new MoneyType("Cent", 1, 19);
public static readonly MoneyType Nickel = new MoneyType("Nickel", 5, 25);
public static readonly MoneyType Dime = new MoneyType("Dime", 10, 30);
public static readonly MoneyType QuarterDollar = new MoneyType("QuarterDollar", 25, 15);
public static readonly MoneyType HalfDollar = new MoneyType("HalfDollar", 50, 100);
public static readonly MoneyType Dollar = new MoneyType("Dollar", 100, 29);
public MoneyType(string key, int value, int diameter)
: base(key, value, diameter)
{
}
public static ReadOnlyCollection<MoneyType> GetValues()
{
return GetBaseValues();
}
public static MoneyType GetByKey(string key)
{
return GetBaseByKey(key);
}
}
#endregion
public class Test
{
public Test()
{
foreach (MoneyType rating in MoneyType.GetValues())
{
Console.Out.WriteLine("Key:{0} Value:{1}", rating.Key, rating.Value);
if (rating == MoneyType.Dollar)
{
Console.Out.WriteLine("This is a dollar!");
}
}
foreach (MoneyType rating in MoneyType.GetValues())
{
if (rating.Diameter == MoneyType.Nickel.Diameter)
{
Console.Out.WriteLine("This is a Nickel diameter!");
}
}
}
}
source
EDIT:
Just found this: Type-safe-enum pattern
An enum is nothing more than an INT value with a name. It stores only one discrete value. What you want to use is a class.
UPDATE:
Sorry, about my mistake. It's actually been quite awhile since I've used C#. To make it up I've written out what I mean:
enum CoinType {
Cent=1,
Nickel=5,
Dime=10,
QuarterDollar=25,
HalfDollar=50,
Dollar=100,
}
class Coin {
public CoinType type;
public int Diameter {
get {
switch (type) {
case CoinType.Cent: return 19;
case CoinType.Nickel: return 25;
case CoinType.Dime: return 20;
case CoinType.QuarterDollar: return 40;
case CoinType.HalfDollar: return 40;
case CoinType.Dollar: return 40;
}
return 0;
}
}
}
You can add custom attributes onto the enum members.
enum CoinType
{
[Value=1]
[Diameter=19]
Cent,
...
}
You can then use reflection to get the info from the attributes.
You just need a mapping from CoinType to diameter and another from CoinType to value. Both can be done with a simple switch statement.
enum CoinType
{
Cent,
Nickel,
Dime,
QuarterDollar,
HalfDollar,
Dollar,
}
static class CoinTypeExts
{
static double Diameter(this CoinType coinType)
{
switch (coinType)
{
case Cent: return 19;
etc...
}
}
static double Value(this CoinType coinType)
{
switch (coinType)
{
case CoinType.Cent: return 1.0;
etc...
}
}
}
Related
Not sure how to phrase this, but I have a class called Lane for different lanes of a road.
A Lane has two parts - the Direction (an Enum of left or right or other) and then the number, an integer. So lanes look like this: L1, L2, R1, R3 etc..
There should only be one instance of the lane class for each lane. L1 shouldn't exist twice.
Because of this, I want to be able to assign the Lane of an object the way you can assign an enum, by typing Lane.L1 or Lane.R4 etc.. I currently have to use a method which finds the existing Lane object that corresponds to the Lane I'm trying to reference.
Is this a way to do this better? Like by simply typing lane = Lane.L1, other than making the Lane class have private constructors and manually creating a public Getter for each possible Lane and assigning references in a static constructor for the Lane class?
This is the current state of the lane class:
public enum Direction { INCREASING = 1, DECREASING = 2, BOTH = 3, OTHER = 4, UNSPECIFIED = 5 }
public class Lane : IComparable
{
public Direction Direction;
public int Number = 1;
public Lane(Direction direction, int number = 1)
{
Direction = direction;
Number = number;
}
public override string ToString()
{
if (Direction == Direction.UNSPECIFIED)
{
return Direction.AsCharLR().ToString();
}
return Direction.AsCharLR() + Number.ToString();
}
public override bool Equals(object obj)
{
if (obj is Lane)
{
Lane l = obj as Lane;
return Direction == l.Direction && Number == l.Number;
}
return false;
}
public override int GetHashCode()
{
return (int)Direction * 100 + Number;
}
public static Lane Parse(char lane)
{
lane = char.ToUpper(lane);
switch (lane)
{
case 'L':
case 'I':
return new Lane(Direction.INCREASING);
case 'R':
case 'D':
return new Lane(Direction.DECREASING);
case 'B':
return new Lane(Direction.BOTH);
case 'U':
return new Lane(Direction.UNSPECIFIED);
case 'O':
default:
return new Lane(Direction.OTHER);
}
}
public static Lane Parse(string text)
{
Lane lane = Parse(text[0]);
lane.Number = int.Parse(text.Substring(1));
return lane;
}
public int CompareTo(object l)
{
return GetHashCode() - l.GetHashCode();
}
}
You can't do what you want with an enum because it doesn't sound like you're placing a limit on the "number" part, and you can't define or use new enums at runtime.
This might be all you need:
public static class Lanes
{
private static readonly Dictionary<string, Lane> LanesDictionary =
new Dictionary<string, Lane>();
public static Lane GetLane(Direction direction, int number)
{
var key = direction.ToString() + number;
if (LanesDictionary.ContainsKey(key))
{
return LanesDictionary[key];
}
var lane = new Lane(direction, number);
LanesDictionary.Add(key, lane);
return lane;
}
}
Now every time you reference Lanes.GetLane(Direction.INCREASING, 4) you'll always get the same Lane. If it doesn't already exist it will be created.
That gets you a convenient, readable way to reference a given lane. If for some reason you wanted shorthand for some lanes - although, as mentioned, you don't want to hardcode them (I wouldn't either) - you could do this:
public static Lane L4 { get; } = GetLane(Direction.INCREASING, 4);
Ok, you said you didn't want private constructors, but what if you had public static attributes, like the following?:
public class Lane
{
private Direction direction;
private int number;
public static Lane L1 = new Lane(Direction.INCREASING, 1);
public static Lane L2 = new Lane(Direction.INCREASING, 2);
//add more ...
private Lane() { }
private Lane(Direction d, int n)
{
this.direction = d;
this.number = n;
}
public enum Direction
{
INCREASING = 1, DECREASING = 2, BOTH = 3, OTHER = 4, UNSPECIFIED = 5
}
}
This way you can type lane = Lane.L1, and it always return the same instance.
Is this enough?
I am facing problem when I am trying to create dictionary, where key is System.Enum. Problem is, that dictionary like this allocates garbage because default EqualityComparer is not one of the best. I tryed to write my own comparer, but without any success. Is it somehow possible?
public enum MyEnum
{
One, Two, Three
}
public Dictionary<Enum, string> dict = new Dictionary<Enum, string>();
public void Test()
{
this.dict.Add(MyEnum.One, "One");
this.dict.Add(MyEnum.Two, "Two");
this.dict.Add(MyEnum.Three, "Three");
string result;
this.dict.TryGetValue(MyEnum.Two, out result); // <-- memory alocation :-(
}
No boxing, no heap allocations. Very fast. No need to write a specific comparer for each enum.
This version will work on any enum as long as its underlying Type isn't more than 32-bits (so byte, ushort, uint are all fine).
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
public sealed class EnumComparer<T> : IEqualityComparer<T>
{
[StructLayout(LayoutKind.Explicit)]
private struct Transformer
{
[FieldOffset(0)]
public T t;
[FieldOffset(0)]
public int int32;
}
public static EnumComparer<T> Default { get; } = new EnumComparer<T>();
private EnumComparer()
{
}
public bool Equals(T a, T b)
{
Transformer aTransformer = new Transformer { t = a };
Transformer bTransformer = new Transformer { t = b };
return aTransformer.int32 == bTransformer.int32;
}
public int GetHashCode(T value)
{
Transformer valueTransformer = new Transformer { t = value };
return valueTransformer.int32.GetHashCode();
}
}
If you want to use it with arrays, you'll probably want to make some extension methods and then you can use it like this:
bool contained = enumArray.Contains(MyEnum.someValue, EnumComparer<MyEnum>.Default);
public static class Extensions
{
public static bool Contains<T>(this T[] array, T value, IEqualityComparer<T> equalityComparer)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
return Extensions.IndexOf<T>(array, value, 0, array.Length, equalityComparer) >= 0;
}
public static int IndexOf<T>(this T[] array, T value, IEqualityComparer<T> equalityComparer)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
return Extensions.IndexOf<T>(array, value, 0, array.Length, equalityComparer);
}
public static int IndexOf<T>(this T[] array, T value, int startIndex, int count, IEqualityComparer<T> equalityComparer)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (count < 0 || startIndex < array.GetLowerBound(0) || startIndex - 1 > array.GetUpperBound(0) - count)
{
throw new ArgumentOutOfRangeException();
}
int num = startIndex + count;
for (int i = startIndex; i < num; i++)
{
if (equalityComparer.Equals(array[i], value))
{
return i;
}
}
return -1;
}
}
Seeing your example in the comments, and that this is for Unity, watch this clip from Unite 2016. It talks about using Scriptable Objects instead of enums for dictionary keys.
What you would do is have
public class Program
{
protected Dictionary<ScriptableObject, string> dict = new Dictionary<ScriptableObject, string>();
}
public class ProgramChild1 : Program
{
public void Test()
{
dict.Add(MyEnum1.One.Instance, "One");
dict.Add(MyEnum1.Two.Instance, "Two");
dict.Add(MyEnum1.Three.Instance, "Three");
string result;
dict.TryGetValue(MyEnum1.Two.Instance, out result);
}
}
public class ProgramChild2 : Program
{
public void Test()
{
dict.Add(MyEnum2.Four.Instance, "One");
dict.Add(MyEnum2.Five.Instance, "Two");
dict.Add(MyEnum2.Six.Instance, "Three");
string result;
dict.TryGetValue(MyEnum2.Five.Instance, out result);
}
}
//Each class goes in to its own .cs file, Put them in two folders `MyEnum1` and `MyEnum2`
namespace MyEnum1
{
public class One : ScriptableObject
{
private static One _inst;
public static One Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<One>();
if (!_inst)
_inst = CreateInstance<One>();
return _inst;
}
}
}
}
namespace MyEnum1
{
public class Two : ScriptableObject
{
private static Two _inst;
public static Two Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<Two>();
if (!_inst)
_inst = CreateInstance<Two>();
return _inst;
}
}
}
}
namespace MyEnum1
{
public class Three : ScriptableObject
{
private static Three _inst;
public static Three Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<Three>();
if (!_inst)
_inst = CreateInstance<Three>();
return _inst;
}
}
}
}
namespace MyEnum2
{
public class Four : ScriptableObject
{
private static Four_inst;
public static Four Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<Four>();
if (!_inst)
_inst = CreateInstance<Four>();
return _inst;
}
}
}
}
namespace MyEnum2
{
public class Five : ScriptableObject
{
private static Five _inst;
public static Five Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<Five>();
if (!_inst)
_inst = CreateInstance<Five>();
return _inst;
}
}
}
}
namespace MyEnum2
{
public class Six : ScriptableObject
{
private static Six _inst;
public static Six Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<Six>();
if (!_inst)
_inst = CreateInstance<Six>();
return _inst;
}
}
}
}
Note that the reason we inherit from ScriptableObject is if you wanted to expose a enum to the designer you could then drag and drop the enum value right in the designer, you could not do this if the enums where just basic classes.
public class ProgramChild2 : Program
{
public ScriptableObject SelectedValue;
public void Test()
{
dict.Add(MyEnum2.Four.Instance, "One");
dict.Add(MyEnum2.Five.Instance, "Two");
dict.Add(MyEnum2.Six.Instance, "Three");
string result;
dict.TryGetValue(SelectedValue, out result);
}
}
You should write a class that implements the interface IEqualityComparer.
class MyEnumComparer : IEqualityComparer<MyEnum> { ... }
Which means you need to implement both bool Equals(MyEnum, MyEnum) and int GetHashCode(MyEnum) functions defined by the IEqualityComparer interface.
Finally when you are creating your Dictionary, use the constructor overload that receives an IEqualityComparer instance, like this:
static MyEnumComparer myEnumComparer = new MyEnumComparer();
...
Dictionary<MyEnum, string> dict = new Dictionary<MyEnum, string>(myEnumComparer);
Solution proposed by #Executor do not work on .Net framework or .Net Core
because of this Why can't generic types have explicit layout?
But if replace EnumComparer<T> from this solution with ConvertToLong from Dissecting new generic constraints in C# 7.3 it will give solution working on full frameworks.
We all know, that in C# an ENUM Type cannot defined with numbers (integers)
e.g. public enum SOME_INTEGERS {3,6,8,11} is not possible
So my question is, how can I define such a resticted type of integers (set of some selected integers) in C#?
In other words, I want to define a variable like this:
private SOME_INTEGERS myVariable;
myVariable may only have the values 3,6,8 or 11
You can use something like this:
public enum SOME_INTEGERS {
One = 1,
Three = 3,
Five = 5
}
SOME_INTEGERS integer = SOME_INTEGERS.Three;
Console.WriteLine((int)integer);//3
Here are some options:
// note that ((SomeIntegers)1) is a valid value with this scheme
public enum SomeIntegers { Three = 3, Six = 6, Eight = 8, Eleven = 11 }
// this stores the set of integers, but your logic to ensure the variable is
// one of these values must exist elsewhere, e.g. in property getters/setters
public ISet<int> SomeIntegers = new HashSet<int> {3,6,8,11};
// this class is a pseudo-enum, and with the exception of reflection,
// will ensure that only the specified values can be set
public sealed class SomeIntegers
{
public static readonly SomeIntegers Three = new SomeIntegers(3);
public static readonly SomeIntegers Six = new SomeIntegers(6);
public static readonly SomeIntegers Eight = new SomeIntegers(8);
public static readonly SomeIntegers Eleven = new SomeIntegers(11);
public int Value { get; private set; }
private SomeIntegers(int value)
{
this.Value = value;
}
public static implicit operator int(SomeIntegers someInteger)
{
return someInteger.Value;
}
public static explicit operator SomeIntegers(int value)
{
switch (value)
{
case 3:
return Three;
case 6:
return Six;
case 8:
return Eight;
case 11:
return Eleven;
default:
throw new ArgumentException("Invalid value", "value");
}
}
public override string ToString()
{
return this.Value.ToString();
}
}
Maybe a struct:
struct MyInt
{
static readonly int[] legalValues = { 3, 6, 8, 11 };
public int Value
{
get;
private set;
}
public bool IsIllegal
{
get
{
return Value == 0;
}
}
MyInt(int value)
: this()
{
Value = value;
}
public static implicit operator MyInt(int value)
{
if (legalValues.Contains(value))
{
return new MyInt(value);
}
return new MyInt();
}
}
But you can create illegal values.
This question already has answers here:
C# vs Java Enum (for those new to C#)
(13 answers)
Closed 9 years ago.
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 are one of the few language features that is better implemented in java than c#.
In java, enums are full fledged named instances of a type, while c# enums are basically named constants.
That being said, for the basic case, they will look similar. However in java, you have more power, in that you can add behavior to the individual enums, as they are full fledged classes.
is there some feature in particular you are looking for?
Here's another interesting idea. 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's Operator example 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.
You could probably use the old typesafe enum pattern that we used in Java before we got real ones (assuming that the ones in C# really aren't classes as a comment claims). The pattern is described just before the middle of this page
//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);
}
}
}
enum , or do you need something in particular that Java enums have but c# doesn't ?
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 ...]
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
}
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;
}
}
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!
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)
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
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)
{
}
}
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.
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.
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.
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
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.
//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);
}
}
}
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
}