I have created the following class:
namespace com.censureret.motions
{
public class EnumPlayerStances {
public const int OneHandSword = 50;
/// <summary>
/// Friendly name of the type
/// </summary>
public static string[] Names = new string[] {
"One handed Sword"
};
}
}
Now I wish to use this in my following class:
namespace com.censureret.motions{
public class OneHandSword_Idle : MotionControllerMotion
{
public override bool TestActivate()
{
if (!mIsStartable) { return false; }
if (!mMotionController.IsGrounded) { return false; }
if (mActorController.State.Stance != EnumPlayerStances.OneHandSword)
return false;
}
}
}
However Visual Studio says it's an error.
I'm fairly new to C#. What can I try next?
You defeated the point of an enum. It should be declared and used like this:
using System;
namespace StackOverflow_Events
{
class Program
{
static void Main(string[] args)
{
string enumName = Enum.GetName(typeof(EnumPlayerStances), EnumPlayerStances.One_Handed_Sword).Replace("_", " ");
int value = (int)EnumPlayerStances.One_Handed_Sword;
var example = EnumPlayerStances.One_Handed_Sword;
switch (example)
{
case EnumPlayerStances.One_Handed_Sword:
// do stuff
break;
}
Console.WriteLine($"Name: {enumName}, Value: {value}");
Console.ReadKey();
}
}
public enum EnumPlayerStances
{
One_Handed_Sword = 50
}
}
Note that it's declared as "enum" not "class".
Also note, that if you declare the enum like:
public enum EnumPlayerStances
{
No_Sword, // 0
One_Handed_Sword, // 1
Two_Handed_Sword // 2
}
The value of the first name begins at 0 and autoincrements by 1 for each following name.
Related
I'm trying to make a menu for a console, and I have this code:
public class Option { /* Id, Name, & constructor */ }
public abstract class Menu {
protected const int rawId = 0;
protected Menu() {
int i = 0;
// CS1579: foreach statement cannot operate on variables of type 'Menu.Menu' because 'Menu.Menu' does not contain a public instance definition for 'GetEnumerator'
foreach (Option o in this) { o.Id = ++i; } // Assigns an id to each option in inherited menus
}
}
public class MMain:Menu {
Option OpenFile = new Option(rawId, "Open File");
Option ExitProgram = new Option(rawId, "Terminate Program");
public MMain():base() { }
}
int Prompt(/* menu to be displayed */) { /* List options; Return selected by id }
So that in the main program, I can do this:
switch (Prompt(/* MMain this case */)) {
case MMain.OpenFile.Id: { /* Opens A File */ break; }
case MMain.ExitProgram.Id: { /* Exits */ break; }
}
Problem is, this in foreach needs a GetEnumerator thing, which I failed to enumerate Options from both the base and the inherited class. Lack of Option should return at least an empty object.
I'm avoiding:
string comparison with switch (hurts efficiency, so I introduced id)
use of enum (tried it, cannot be used as parameters for function, made a mess)
tailoring a function for each menu (hard to maintain, kills consistency)
Is there any way to accomplish this?
Unsuccessful Approach with enum (bg info)
Fine to ignore. Included in case being asked to try enum, tried this:
public class MMain {
public enum Option { OpenFile, ExitProgram /* and more */ }
public static string NameOf(Option o) {
return o switch {
Option.OpenFile => "Open File",
Option.ExitProgram => "Terminate Program",
_ => throw new ArgumentException(InvMO)
};
}
public static Option Prompt() {
ListOptions(typeof(Option));
/* return Choice(...); */
}
private static void ListOptions(Type t) {
foreach (var option in Enum.GetValues(t)) {
// CS1503: cannot convert from 'object' to 'Option'
Console.WriteLine(NameOf(option));
/* Also if casting like this: Console.WriteLine((t)NameOf(option))
it will give CS0118: 't' is a variable but is used like a type */
}
}
}
and this:
/* ... */
public static Option Prompt() {
Option opts;
ListOptions(opts); // Unable to declare a function that inputs all types of enum
/* ... */
So that in the main program:
switch (MMain.Prompt()) {
case MMain.Option.OpenFile: { /* Opens A File */ break; }
case MMain.Option.ExitProgram: { /* Exits */ break; }
}
Credits
Guidance of my code as follows:
Associating enums with strings in C#, source of the whole idea for replacing enum, really
Constructor inheritance
For the enum approach:
class EnumLoop<Key> where Key : struct, IConvertible, felt it was so close but eventually didn't work it out myself, therefore gave up enum
foreach (Suit suit in (Suit[]) Enum.GetValues(typeof(Suit))), cannot pass enum hence cannot create Option opt in (Option[])Enum.GetValues(typeof(Option)))
Creating variable with System.Type (Passing typeof(Option) to a function, to create Option opt in the function, unable to work it out too)
I don't know if I understand your question very well, but this problem could be worked around using reflections, or, a much easier approach, working as a list of options within the menu, like this:
using static MMain;
var main = new MMain();
switch ((MMainOptions)main.Prompt())
{
case MMainOptions.OpenFile:
Console.WriteLine($"Chosen option: Open file");
break;
case MMainOptions.TerminateProgram:
Console.WriteLine($"Chosen option: Terminate program");
break;
}
Console.ReadKey();
public class Option
{
public int Id { get; set; }
public string Name { get; set; }
public Option(int id, string name)
{
Id = id;
Name = name;
}
public Option() { }
}
public abstract class Menu
{
protected List<Option> Options { get; set; }
protected Menu()
{
Options = new List<Option>();
}
public int Prompt()
{
Console.WriteLine("{0,2}{1,2}", "Id", "Name");
foreach (var option in Options)
{
Console.WriteLine("{0,2}{1,2}", option.Id, , option.Name);
}
Console.WriteLine("Type id:");
var result = Console.ReadLine();
return Convert.ToInt32(result);
}
}
public class MMain : Menu
{
public enum MMainOptions
{
OpenFile = 1,
TerminateProgram = 2
}
public MMain() : base()
{
Options.Add(new Option((int)MMainOptions.OpenFile, "Open File"));
Options.Add(new Option((int)MMainOptions.TerminateProgram, "Terminate Program"));
}
}
Hope this helps
How do I separate my code into their own classes and still have it function the same? This is currently what my code looks like.
using System;
using System.Collections.Generic;
using System.Xml;
using XCENT.JobServer.JobPlugIn;
using System.IO;
using HPD.API.Utility.DataAccess;
namespace DataPurge
{
public class Purge : IJob, IJobControl {
public IJobControl JobControl { get { return ( this ); } }
public int MaxInstanceCount { get { return 1; } }
public string Name { get { return "DataPurge"; } }
public Purge() { }
public void Run( string XmlFragment ) {
XmlNode xmlNode = null;
try
{
xmlNode = Common.ConstructXmlNodeFromString(XmlFragment, "Params");
var list = DataList();
foreach (var item in list)
{
var factory = new PurgerFactory(item);
IPurger purge = factory.Purger;
purge.Purge();
purge = null;
factory = null;
}
}
catch (Exception ex)
{
throw;
}
}
public interface IPurger
{
void Purge();
}
public enum PurgeType
{
File,
Database,
}
public class FilePurger : IPurger
{
private Parameters parameter;
public FilePurger(Parameters parameter)
{
this.parameter = parameter;
}
public void Purge()
{
var files = new DirectoryInfo(parameter.FilePath).GetFiles();
foreach (var file in files)
{
if (DateTime.Now - file.CreationTime > TimeSpan.FromDays(7))
{
File.Delete(file.FullName);
}
}
}
}
public class DbPurger : IPurger
{
private Parameters parameter;
public DbPurger(Parameters parameter)
{
this.parameter = parameter;
}
public void Purge()
{
var access = new SqlDataAccess();
var sqlParams = new Dictionary<string, object>();
sqlParams.Add("#OlderThanDays", parameter.OlderThanDays);
access.ExecuteNonQuery(parameter.CString, parameter.SPName, sqlParams, 30, false);
}
}
private List<Parameters> DataList()
{
var sqlParams = new SqlDataAccess();
var list = sqlParams.GetDataTableAsList<Parameters>("Data Source = MYSERVER; Initial Catalog = MYDATABASE; User ID = UID; Password = PASSWORD;", "purge.spoDataTable", null);
return list;
}
public class PurgerFactory
{
public IPurger Purger { get; set; }
public PurgerFactory(Parameters parameter)
{
PurgeType type = (PurgeType)Enum.Parse(typeof(PurgeType), parameter.PurgeType);
switch (type)
{
case PurgeType.File:
Purger = new FilePurger(parameter);
break;
case PurgeType.Database:
Purger = new DbPurger(parameter);
break;
default:
throw new NotImplementedException();
}
}
}
/// <summary>
/// Used to submit a job via the job monitor
/// </summary>
public XmlNode JobXMLNode => Common.ConstructXmlNodeFromString("" +
"<JobParams>" +
" <Param Name=\"InfrastructureAPI\" DataType=\"String\">" +
" <Description>Infrastructure API URL.</Description>" +
" </Param>" +
" <Param Name=\"EnvironmentName\" DataType=\"String\">" +
" <Description>The current environment.</Description>" +
" </Param>" +
"</JobParams>",
"JobParams");
}
}
Currently all parts of the program are stuffed into this one single class. I want to separate them out into their own separate classes to make the code much cleaner but still have it function the same. I'm still a beginner coder and don't know the first place to start. Any help would be much appreciated!
You should create a file IPurger.cs for the interface IPurger, then a file FilePurger.cs for the class FilePurger, the file DbPurger.cs for the class DbPurger and lastly PurgerFactory.cs for the class PurgerFactory.
That should clean up your code quite well.
If that enum is used from multiple places, you may want to place it in its own class too, perhaps a generic Enums.cs.
I have created an interface that in theory should be able to return multiple generic lists of different types to provide the client with various information. When I attempt to loop through the results of the list it is only able to return first collection, can you help me to understand how I should be returning results from the following:
Interface class:
public interface IExampleInterface{}
public class ExampleType : IExampleInterface
{
public int First;
public int Last;
}
public class ExampleAmount : IExampleInterface
{
public decimal Amount;
public decimal TotalFee;
}
public class ExampleFacts : IExampleInterface
{
public bool TooLow;
public bool TooHigh;
}
Interface provider:
public class ExampleInterfaceProvider
{
private static readonly string conn = ConfigurationManager.ConnectionStrings["conn"].ConnectionString;
public static List<IExampleInterface> ExampleResults(int id)
{
//declare variables, read from database query using ExecuteReader...
var sT = new ExampleType
{
First = first;
Last = last;
}
var sA = new ExampleAmount
{
Amount = amount;
TotalFee = totalFee;
}
var sF = new ExampleFacts
{
TooHigh = tooHigh;
TooLow = tooLow;
}
var exampleResults = new List<IExampleInterface> {sT, sA, sF};
return exampleResults;
}
}
On the page I need to return the data:
foreach (dynamic item in ExampleResults(0))
{
Response.Write(item.First.ToString())
Response.Write(item.Last.ToString())
//The first two for 'sT' read fine, it breaks here
Response.Write(item.Amount.ToString())
//... And so on
}
Any help would be much appreciated,
Thanks
I think, there is no another solution except comparing implementations;
foreach (IExampleInterface item in ExampleResults(0))
{
if (item is ExampleType)
{
var exampleType = (ExampleType)item;
Response.Write(exampleType.First.ToString())
Response.Write(exampleType.Last.ToString())
}
else if (item is ExampleAmount)
{
var exampleAmount = (ExampleAmount)item;
Response.Write(exampleAmount.Amount.ToString())
}
//... And so on
}
If you are using C# 7, you can perform it as switch case
foreach (IExampleInterface item in ExampleResults(0))
{
switch (item)
{
case ExampleType c:
Response.Write(c.First.ToString());
Response.Write(c.Last.ToString());
break;
case ExampleAmount c:
Response.Write(c.Amount.ToString());
break;
default:
break;
}
//... And so on
}
You can find the documentation.
So basically, the items implementing IExampleInterface should all be written to a Response in a way that is somewhat specific to the actual type implementing the interface?
Then how about this:
public interface IExampleInterface
{
void WriteTo(Response response);
}
public class ExampleType : IExampleInterface
{
public int First;
public int Last;
public void WriteTo(Response response)
{
response.Write(First.ToString());
response.Write(Last.ToString());
}
}
public class ExampleAmount : IExampleInterface
{
public decimal Amount;
public decimal TotalFee;
public void WriteTo(Response response)
{
response.Write(Amount.ToString());
response.Write(TotalFee.ToString());
}
}
public class ExampleFacts : IExampleInterface
{
public bool TooLow;
public bool TooHigh;
public void WriteTo(Response response)
{
response.Write(TooLow.ToString());
response.Write(TooHigh.ToString());
}
}
And then:
foreach (IExampleInterface item in ExampleResults(0))
{
item.WriteTo(Response);
}
Assuming that Response is a variable holding an instance of the response rather than a static class.
I was making a test case for some code on binary search tree my professor gave
public static void Main(string [] args)
{
//on my prof's code, public class BinSearchTree<T>
BinSearchTree<int> myTree = new BinSearchTree<int>();
myTree.Insert(10);
myTree.Insert(15);
myTree.Insert(5);
myTree.Insert(2);
myTree.Insert(1);
Console.WriteLine(myTree.ToString());
Console.ReadKey();
}
It compiles, but it displays
BinSearchTree`1[System.Int32]
Can somebody tell me why it displays that?
my prof's code:
public class BinSearchTree<T> where T : IComparable<T>
{
private class OurTreeNode<T>
{
public T Data { get; set; }
public OurTreeNode<T> Left;
public OurTreeNode<T> Right;
public OurTreeNode(T d = default(T), OurTreeNode<T> leftnode = null, OurTreeNode<T> rightnode = null)
{
Data = d;
Left = leftnode;
Right = rightnode;
}
public override string ToString()
{
return Data.ToString();
}
}
//...other methods
//prof's Insert method
public void Insert(T newItem)
{
mRoot = Insert(newItem, mRoot);
}
private OurTreeNode<T> Insert(T newItem, OurTreeNode<T> pTmp)
{
if (pTmp == null)
return new OurTreeNode<T>(newItem, null, null);
else if (newItem.CompareTo(pTmp.Data) < 0)
pTmp.Left = Insert(newItem, pTmp.Left);
else if (newItem.CompareTo(pTmp.Data) > 0)
pTmp.Right = Insert(newItem, pTmp.Right);
else
throw new ApplicationException("...");
return pTmp;
}
}
I tried adding a ToString() method after the Insert method but it gives me an error when I used foreach. Is there a way of displaying it without making too much extra methods?
The class is using the default (Object's) ToString() implementation. You have 2 options:
walk though the elements of the tree and print it yourself
ask the author to implement/override the ToString() method
Can somebody tell me why it displays that?
It displays that because ToString() prints the type definition.
Default implementations of the Object.ToString method return the fully qualified name of the object's type. (from the docs)
For instance, the following short program prints System.Collections.Generic.List`1[System.Int32], which is the type of List<int>.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
List<int> myTree = new List<int>();
myTree.Add(10);
Console.WriteLine(myTree.ToString());
}
}
Here are the rudiments of how to override the ToString() method to produce some meaningful output.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
BinSearchTree<int> myTree = new BinSearchTree<int>();
myTree.Insert(10);
myTree.Insert(15);
Console.WriteLine(myTree.ToString());
}
}
public class BinSearchTree<T> where T : IComparable<T>
{
private List<T> values = new List<T>();
// rest of class omitted for clarity
public void Insert(T val) {
values.Add(val);
}
public override string ToString() {
var result = string.Empty;
foreach(var v in values)
{
result += v + ", ";
}
return result;
}
}
Output
10, 15,
As you have created the object of BinaryTree Class and have not overridden the ToString() method inside BinaryTree Class. You have not created object of OurTreeNode class and not calling ToString() method overriden inside it. Hence it is giving you the default ToString() method output of BinaryTree Class.
BinSearchTree<int> myTree = new BinSearchTree<int>();
You are calling
Console.WriteLine(myTree.ToString());
Is it possible to copy this functionality of offering an abstract method in an enum that inner enum constants must override and provide functionality to?
public enum Logic {
PAY_DAY {
#Override
public void acceptPlayer(Player player) {
// Perform logic
}
},
COLLECT_CASH {
#Override
public void acceptPlayer(Player player) {
// Perform logic
}
}
,
ETC_ETC {
#Override
public void acceptPlayer(Player player) {
// Perform logic
}
};
public abstract void acceptPlayer(Player player);
}
If it can't::
Could you provide a way which I can implement lots of specific logic in a similar manner?
Edit :: I know that enums in C# are not really 'objects' like they are in Java, but I wish to perform similar logic.
Edit :: To clarify, I do not want to provide concrete classes for each specific bit of logic. IE, creating an interface acceptPlayer and creating many new classes is not appropiate
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.
If you don't want to use interfaces and a class hierarchy, you could use delegates, something like :
public class Player{}
public static class Logic
{
public static readonly Action<Player> PAY_DAY = p => Console.WriteLine( "Pay day : " + p.ToString());
public static readonly Action<Player> COLLECT_CASH = p=> Console.WriteLine(p.ToString ());
public static void AcceptPlayer( this Action<Player> PlayerAction, Player ActingPlayer )
{
PlayerAction(ActingPlayer);
}
}
class MainClass
{
public static void Main (string[] args)
{
var player = new Player();
Logic.PAY_DAY.AcceptPlayer( player );
}
}
I like the advantages of Java enums and wanted to try to simulate them. I have looked at many posts here and could not find a simple way to do this so I came up with the following. I am not a professional so please forgive me for any stupid mistakes.
This, I beleive, provides almost all of the functionality to a Java enum (I did not write a clone method).
Also, I apologize for the length of this post.
This is the abstract class:
#region + Using Directives
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using TestEnum;
#endregion
namespace TestEnum
{
public abstract class ACsEnum<T, U, V> :
IComparable<ACsEnum<T, U, V>>
where T : ACsEnum<T, U, V>
{
static ACsEnum()
{
// the static constructor causes
// early creation of the object
Count = 0;
}
// constructor
protected ACsEnum(Enum m, V v)
{
Enum = m;
Value = v;
Ordinal = Count++;
}
#region Admin Private fields
// the list of members
protected static readonly List<T> members = new List<T>();
#endregion
#region Admin Public Properties
// the enum associated with this class
public Enum Enum { get; }
// number of members
public static int Count { get; private set; }
// ordinal number of this member (zero based)
public int Ordinal { get; }
// a name of this member
public string Name => ToString();
// the value attached to the enum
public U Amount => (U) (IConvertible) Enum;
// the value of this member - this value is
// returned from the implicit conversion
public V Value { get; }
#endregion
#region Admin Operator
public static implicit operator V (ACsEnum<T, U, V> m)
{
return m.Value;
}
#endregion
#region Admin Functions
// compare
public int CompareTo(ACsEnum<T, U, V> other)
{
if (other.GetType() != typeof(T)) { return -1; }
return Ordinal.CompareTo(other.Ordinal);
}
// determine if the name provided is a member
public static bool IsMember(string name, bool caseSensitive)
{
return Find(name, caseSensitive) != null;
}
// finds and returns a member
public static T Find (string name, bool caseSensitive = false)
{
if (caseSensitive)
{
return members.Find(s => s.ToString().Equals(name));
}
else
{
return members.Find(s => s.ToString().ToLower().Equals(name.ToLower()));
}
}
// allow enumeration over the members
public static IEnumerable Members()
{
foreach (T m in members)
{
yield return m;
}
}
// get the members as an array
public static T[] Values()
{
return members.ToArray();
}
// same as Find but throws an exception
public static T ValueOf(string name)
{
T m = Find(name, true);
if (m != null) return m;
throw new InvalidEnumArgumentException();
}
#endregion
#region Admin Overrides
public override bool Equals(object obj)
{
if (obj != null && obj.GetType() != typeof(T)) return false;
return ((T) obj).Ordinal == Ordinal ;
}
#endregion
}
}
This is an extension method to help with enum's:
namespace TestEnum
{
// special enum extension that gets the value of an enum
//
public static class EnumEx
{
public static dynamic Value(this Enum e)
{
switch (e.GetTypeCode())
{
case TypeCode.Byte:
{
return (byte) (IConvertible) e;
}
case TypeCode.Int16:
{
return (short) (IConvertible) e;
}
case TypeCode.Int32:
{
return (int) (IConvertible) e;
}
case TypeCode.Int64:
{
return (long) (IConvertible) e;
}
case TypeCode.UInt16:
{
return (ushort) (IConvertible) e;
}
case TypeCode.UInt32:
{
return (uint) (IConvertible) e;
}
case TypeCode.UInt64:
{
return (ulong) (IConvertible) e;
}
case TypeCode.SByte:
{
return (sbyte) (IConvertible) e;
}
}
return 0;
}
}
}
This is the actual "enum" class:
namespace TestEnum
{
public class Planet : ACsEnum<Planet, byte, double>
{
#region Base enum
// this holds the position from the sun
public enum planet : byte
{
MERCURY = 1,
VENUS = 2,
EARTH = 3,
MARS = 4,
JUPITER = 5,
SATURN = 6,
URANUS = 7,
NEPTUNE = 8,
PLUTO = 9
}
#endregion
#region ctror
// planet enum, mass, radius, orbital period (earth days)
private Planet( planet p, double m, double r, double v) : base(p, v)
{
Mass = m;
Radius = r;
members.Add(this);
}
#endregion
#region enum specific Properties
public double Mass { get; }
public double Radius { get; }
#endregion
#region enum specific Functions
public static double G = 6.67300E-11;
public double SurfaceGravity()
{
return (G * Mass) / (Radius * Radius);
}
public double SurfaceWeight(double otherMass)
{
return otherMass * SurfaceGravity();
}
#endregion
#region Overrides
public override string ToString() => Enum.ToString();
#endregion
#region Members
// enum mass radius "year"
public static readonly Planet MERCURY = new Planet(planet.MERCURY, 3.303e+23 , 2.4397e6 , 88.0);
public static readonly Planet VENUS = new Planet(planet.VENUS , 4.869e+24 , 6.0518e6 , 224.7);
public static readonly Planet EARTH = new Planet(planet.EARTH , 5.976e+24 , 6.37814e6 , 365.2);
public static readonly Planet MARS = new Planet(planet.MARS , 6.421e+23 , 3.3972e6 , 687.0);
public static readonly Planet JUPITER = new Planet(planet.JUPITER, 1.9e+27 , 7.1492e7 , 4331.0);
public static readonly Planet SATURN = new Planet(planet.SATURN , 5.688e+26 , 6.0268e7 , 10747.0);
public static readonly Planet URANUS = new Planet(planet.NEPTUNE, 8.686e+25 , 2.5559e7 , 30589.0);
public static readonly Planet NEPTUNE = new Planet(planet.URANUS , 1.024e+26 , 2.4746e7 , 59800.0);
public static readonly Planet PLUTO = new Planet(planet.PLUTO , 11.30900e+22 , 1.187e6 , 90560.0);
#endregion
}
}
Lastly, here is the usage example:
using System;
using static TestEnum.Planet;
namespace TestEnum
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.EnumTest();
Console.WriteLine("\n\nWaiting ...: ");
Console.ReadKey();
}
private void EnumTest()
{
// test:
// each admin property: count, ordinal, value, name
// each unique property: APlanet, Mass, Radius, G
// implicit operator
// admin functions:
// admin overrides:
// unique properties
// unique functions
Console.WriteLine("\nadmin properties\n");
Console.WriteLine("count | " + Planet.Count + " (== 9)");
Console.WriteLine("ordinal | " + MERCURY.Ordinal + " (== 0)");
Console.WriteLine("name | " + MERCURY.Name + " (== MERCURY)");
Console.WriteLine("value | " + MERCURY.Value + " (== 88 Mercury year)");
double x = EARTH;
Console.WriteLine("\nadmin Operator\n");
Console.WriteLine("Year | " + x + " (== 365.2 year)");
Console.WriteLine("\nadmin functions\n");
Console.WriteLine("Compare to| " + MERCURY.CompareTo(EARTH) + " (== -1)");
Console.WriteLine("IsMember | " + Planet.IsMember("EARTH", true) + " (== true)");
Console.WriteLine("Find | " + Planet.Find("EARTH", true).Name + " (== EARTH)");
Console.WriteLine("ValueOf | " + Planet.ValueOf("EARTH").Name + " (== EARTH)");
Console.WriteLine("Equals | " + EARTH.Equals(MERCURY) + " (== false => EARTH != MERCURY)");
Console.WriteLine("\n\nunique admin\n");
Console.WriteLine("G | " + Planet.G);
Console.WriteLine("\nunique properties\n");
Console.WriteLine("Enum | " + MERCURY.Enum);
Console.WriteLine("Mass | " + MERCURY.Mass);
Console.WriteLine("Radius | " + MERCURY.Radius);
Console.WriteLine("amount | " + MERCURY.Amount + " (== 1 MERCURY first planet)");
Console.WriteLine("\n\nunique functions");
// typical Java enum usage example
double earthWeight = 175; // lbs
double mass = earthWeight / EARTH.SurfaceGravity();
Console.WriteLine("\ncalc weight via foreach\n");
foreach (Planet p in Planet.Members())
{
Console.WriteLine("Your weight on {0} is {1:F5}",
p.Name, p.SurfaceWeight(mass));
}
// end, typical Java enum usage example
// test Values
Planet[] planets = Planet.Values();
Console.WriteLine("\ncalc weight via array\n");
foreach (Planet p in planets)
{
Console.WriteLine("Your weight on {0} is {1:F5}",
p.Name, p.SurfaceWeight(mass));
}
// test switch
Planet planet = PLUTO;
Console.WriteLine("\nuse switch - looking for PLUTO\n");
switch (planet.Enum)
{
case Planet.planet.EARTH:
{
Console.WriteLine("found EARTH\n");
break;
}
case Planet.planet.JUPITER:
{
Console.WriteLine("found JUPITER\n");
break;
}
case Planet.planet.PLUTO:
{
Console.WriteLine("found PLUTO\n");
break;
}
}
// these will use implicit value
Console.WriteLine("\ntest comparison checks\n");
if (EARTH == EARTH)
{
Console.WriteLine("\npassed - EARTH == EARTH\n");
}
if (MERCURY < EARTH)
{
Console.WriteLine("passed - MERCURY < EARTH\n");
}
if (PLUTO > EARTH)
{
Console.WriteLine("passed - PLUTO > EARTH\n");
}
// test enum extension
Console.WriteLine("\nbonus - enum extension\n");
Console.WriteLine("PLUTO AsShort| " + Planet.planet.PLUTO.Value() + " (9th planet)");
// test ValueOf failure
Console.WriteLine("\n\nValueOf that fails\n");
try
{
planet = Planet.ValueOf("xxx");
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
}
I hope this helps anyone who wants to provide added features to enum's and maybe this will help someone convert their program from Java to C#
In c#, you do this with classes, not enums. Create a base class with the virtual method you want to override.
Each member of the Java enum will be a sub-class with the implementation you want.
Finally, create a read-only static field in the base class for each enum member, initializing it with an instance of the sub-class for that enum value.
Extending the answer by Jon Skeet I found a slightly other approach that even allows you individual behavior / data with an enum similar structure. It is maybe not a real answer to the question, because it does not fulfill:
Edit :: To clarify, I do not want to provide concrete classes for each specific bit of logic. IE, creating an interface acceptPlayer and creating many new classes is not appropiate
The following construct together with C# 7 gives a very enum like syntax:
public abstract class Logic
{
private Logic() { }
public abstract void acceptPlayer(Player player);
public sealed class PayDay : Logic
{
public PayDay(DateTime timeOfPayment)
{
TimeOfPayment = timeOfPayment;
}
public DateTime TimeOfPayment { get; }
public override void acceptPlayer(Player player)
{
// Perform logic
}
}
public sealed class CollectCash : Logic
{
public CollectCash(int amountOfMoney)
{
AmountOfMoney = amountOfMoney;
}
public int AmountOfMoney { get; }
public override void acceptPlayer(Player player)
{
// Perform logic
}
}
public sealed class EtcEtc : Logic
{
public override void acceptPlayer(Player player)
{
// Perform logic
}
};
}
The private constructor of the abstract Logic class and the sealed implementations guarantee that there is only a well defined set of options that are all part of the scope of the Logic class.
Creation looks somewhat unusual:
Logic logic = new Logic.PayDay(DateTime.Now);
But together with C# 7's Pattern Matching it even starts to feel like an enum:
switch (logic)
{
case Logic.PayDay payday:
var timeOfPayment = payday.TimeOfPayment;
// ...
break;
case Logic.CollectCash collectCash:
// ...
break;
// ...
}
And also other test logic is quite readable:
if (logic is Logic.EtcEtc)
{
// ...
}
Or if you need the casted instance:
if (logic is Logic.EtcEtc etcEtc)
{
// ...
}