1

Is it possible in C# to collect information in an enum instead of a dedicated class?

Example how it would work in Java:

  public enum Action {

    JUMP( "JUMP", 1),
    CROUCH ("CROUCH", 2),
    ;

    private String animationId;
    private int buttonId;

    private Action( String animationId, int buttonId) {
      this.animationId = animationId;
      this.buttonId = buttonId;
    }

    public String getAnimationId() {
      return animationId;
    }

    public int getButtonId() {
      return buttonId;
    }
  }
Roland
  • 18,114
  • 12
  • 62
  • 93
  • 4
    You can use `struct` if you don't want a class – JohanP Aug 06 '18 at 04:47
  • 2
    no, but you can use a sealed class with public static fields as enum values – vasily.sib Aug 06 '18 at 04:49
  • `enum` in C# & Java are different construction, see the difference [here](https://stackoverflow.com/questions/469287/c-sharp-vs-java-enum-for-those-new-to-c). – Tetsuya Yamamoto Aug 06 '18 at 05:02
  • Hmmm...how do you enforce uniqueness? –  Aug 06 '18 at 05:07
  • You might want to check out Jon Skeet's [Enhanced enums in C#](https://codeblog.jonskeet.uk/2006/01/05/classenum/) . Not sure of the outcome –  Aug 06 '18 at 05:15
  • Or you could use attributes, a Dictionary, or a class, or a struct, or if you have more relationship data, you can store in a relationship DB – TheGeneral Aug 06 '18 at 05:17
  • @TheGeneral but then you will not be able to use the type `Action` – bluray Aug 06 '18 at 05:20
  • Also check out _[How to implement a type-safe enum pattern in C#](https://www.infoworld.com/article/3198453/application-development/how-to-implement-a-type-safe-enum-pattern-in-c.html)_ –  Aug 06 '18 at 05:30
  • @bluray i agree, for simple constraints and relationships where you want a quick in memory `enum` with the configuration of one or more relationship, i think attributes are a good solution (remembering it does use reflection) i guess the answer comes down to how far down this rabbit whole do we want to go – TheGeneral Aug 06 '18 at 05:33
  • Your enum already contains integer value by default, first is 0, second is 1 and so on. You can also assign those values enum Action { Jump = 10, Crouch = 20 } then int value = (int)Action.Jump; or if((int)action > 10) { // it's a crouch} – Everts Aug 06 '18 at 11:54

3 Answers3

3

You can use enum with attributes:

public enum Action{
  [MyValue("JUMP", 1)]
  JUMP,

  [MyValue("CROUCH", 2)]
  CROUCH
}

[AttributeUsage(
   AttributeTargets.Field |
   AttributeTargets.Method |
   AttributeTargets.Property,
   AllowMultiple = true)]
public class MyValueAttribute : System.Attribute{
  public string Value{get; private set}
  public string AnimationId{get; private set;}
  public MyValueAttribute(string animationId, string value){
     AnimationId = animationId;
     Value = value;
}

and you can get value as follows:

public static class EnumExtensions{
        public static string GetValue(this Enum value)
        {
            var type = value.GetType();
            var name = Enum.GetName(type, value);
            if (name == null) return string.Empty;
            var field = type.GetField(name);
            if (field == null) return string.Empty;
            var attr = Attribute.GetCustomAttribute(field, typeof(MyValueAttribute)) as MyValueAttribute;
            return attr != null ? attr.Value: string.Empty;
        }

        public static string GetAnimationId(this Enum value)
        {
            var type = value.GetType();
            var name = Enum.GetName(type, value);
            if (name == null) return string.Empty;
            var field = type.GetField(name);
            if (field == null) return string.Empty;
            var attr = Attribute.GetCustomAttribute(field, typeof(MyValueAttribute)) as MyValueAttribute;
            return attr != null ? attr.AnimationId: string.Empty;
        }
}

Usage:

Action.JUMP.GetValue();
Action.JUMP.GetAnimationId();

or you can use one method which return for example Tuple with AnimationId and Value

bluray
  • 1,875
  • 5
  • 36
  • 68
2

No, but you can use static class fields instead:

public sealed class Action
{
    public static readonly Action JUMP = new Action("JUMP", 1);
    public static readonly Action CROUCH = new Action("CROUCH", 2);

    public string AnimationId { get; }
    public int ButtonId { get; }

    private Action(String animationId, int buttonId)
    {
        AnimationId = animationId;
        ButtonId = buttonId;
    }

    public override string ToString() => AnimationId;
}
vasily.sib
  • 3,871
  • 2
  • 23
  • 26
  • 2
    _"...static class fields.."_ - That's what's called a _typesafe enum pattern_. _[How to implement a type-safe enum pattern in C#](https://www.infoworld.com/article/3198453/application-development/how-to-implement-a-type-safe-enum-pattern-in-c.html)_ –  Aug 06 '18 at 05:31
  • I guess "No" was the correct answer. The ToString() should't be the AnimationId because my example was just a simple one. The main purpose is to not have out of context identifiers being used in the cs files. – Roland Aug 07 '18 at 08:52
  • @Roland, `ToString` implementation is not necessary and can be changed to anything you need. It is useful, for example, within string interpolation: `var a = $"Base action: {Action.JUMP}!"` – vasily.sib Aug 07 '18 at 09:35
0

You could definitely use attributes like suggested. However, you can call .ToString() on an enum value to get its name as a string value, and you can also assign int values to them. By default they are assigned 0-X based on index. However you could do this

public enum Action {
JUMP=1, 
CROUCH=2
}

And then to access these values

Action action = Action.JUMP;
int value = (int) action; //Is set to 1
string name = action.ToString(); //Is set to "JUMP"

While this certainly will not work in every case depending on how much you want your enum to store, for the situation you described this is much easier.

Andy Riedlinger
  • 301
  • 2
  • 10
  • 1
    What about the `string` _animationId_? –  Aug 06 '18 at 05:08
  • 1
    In your example, you are setting your animationId to what the actual name of your enum value is. Which is string animationId = action.ToString(); If you wanted the animationId to be something other then the name of the enum value, this would not work. – Andy Riedlinger Aug 06 '18 at 05:10