tags:

views:

361

answers:

5

My question is best illustrated with an example.

Suppose I have the enum:

public enum ArrowDirection
{
    North,
    South,
    East,
    West
}

I want to associate the unit vector corresponding to each direction with that direction. For example I want something that will return (0, 1) for North, (-1, 0) for West, etc. I know in Java you could declare a method inside the enum which could provide that functionality.

My current solution is to have a static method -- inside the class that defines the enum -- that returns a vector corresponding to the passed in ArrowDirection (the method uses a HashTable to accomplish the lookup but that's not really important). This seems... unclean.

Question:
Is there a best-practice solution for storing additional information corresponding to an enum in .NET?

+2  A: 

I've blogged about it here.

Try out something like this with Attributes.

  public enum Status {

    [Status(Description = "Not Available")]      

    Not_Available = 1,      

    [Status(Description = "Available For Game")] 

    Available_For_Game = 2,      

    [Status(Description = "Available For Discussion")] 

    Available_For_Discussion = 3,

  }

  public class StatusEnumInfo {

    private static StatusAttribute[] edesc; 

    public static String GetDescription(object e)

    {

      System.Reflection.FieldInfo f = e.GetType().GetField(e.ToString()); 

      StatusEnumInfo.edesc = f.GetCustomAttributes(typeof(StatusAttribute), false) as StatusAttribute[]; 

      if (StatusEnumInfo.edesc != null && StatusEnumInfo.edesc.Length == 1)         

        return StatusEnumInfo.edesc[0].Description; 

      else         

        return String.Empty;

    } 

    public static object GetEnumFromDesc(Type t, string desc)

    {

      Array x = Enum.GetValues(t); 

      foreach (object o in x) {

        if (GetDescription(o).Equals(desc)) {

          return o;

        }

      } return String.Empty;

    }

  }

  public class StatusAttribute : Attribute {

    public String Description { get; set; }

  }



  public class Implemenation {

    public void Run()

    {

      Status statusEnum = (Status)StatusEnumInfo.GetEnumFromDesc(typeof(Status), "Not Available"); 

      String statusString = StatusEnumInfo.GetDescription(Status.Available_For_Discussion);

    }

  }

Instead of Description, use your custom Property

Cherian
+1  A: 

One thing you could look at is the "Type-Safe Enum" pattern. This allows you to create an enum that is actually a full-fledged static object, which can have methods/properties/etc..

http://www.javacamp.org/designPattern/enum.html

Joshua Bloch talks about this pattern in his book "Effective Java." I've used it in a lot of different situations, and I actually prefer it over plain enums. (It's language-agnostic - it works in Java, C#, or pretty much any OO language).

Andy White
I've used it too and like it. But only recently I've found something I like even more. You can put extension methods onto enums! Funny how much enjoyment that brings me ... but it is really nice.
Charlie Flowers
I'll have to check that out, thanks for the info
Andy White
A: 

Your static method approach seems quite clean to me. You encapsulate both the enum and the static method within the same class. Changes to the enum are centralised within that single class.

Adding a method to the enumeration (as per Java) seems to add complexity to something that is really a very simple concept.

The attribute based approach is interesting, but once again seems to overcomplicate things when compared to a static method.

Ash
+11  A: 

There's a FANTASTIC new way to do this in C# 3.0. The key is this beautiful fact: Enums can have extension methods! So, here's what you can do:

public enum ArrowDirection
{
    North,
    South,
    East,
    West
}

public static class ArrowDirectionExtensions
{
     public static UnitVector UnitVector(this ArrowDirection self)
     {
         // Replace this with a dictionary or whatever you want ... you get the idea
         if(self == ArrorDirection.North)
         {
              return new UnitVector(1,1);
         }

         if(self == ArrowDirection.South)
         {
              return new UnitVector(1,1);
         }

         // Etc.
     }
}

Now, you can do this:

var unitVector = ArrowDirection.North.UnitVector();

Sweet! I only found this out about a month ago, but it is a very nice consequence of the new C# 3.0 features.

Here's another example on my blog.

Charlie Flowers
That's pretty cool. Although I knew about extensions I never thought using them for enum extension
Sergej Andrejev
Yeah, me either at first. A friend told me about it. It is very nice. I was also surprised to learn (recently, here on SO) that you can call an extension method on a null value. It still works because it is a static method. As usual, the C# team has done a great job thinking these features through.
Charlie Flowers
You're going to get the accepted answer. I tried it and it works perfectly. The only thing is. Where exactly should I declare the enum? If I leave it in the class, it says it's less accessible. I had to make a "ClassName_Enums" Class to make it work...
colithium
It turns out it makes sense to define the enum at the namespace level. Accepted.
colithium
Yes, I agree that I would go with the namespace level in most cases.
Charlie Flowers
Huh. That's awfully convenient, and I never realized you could build extension methods on enums like that. Cool!
mquander
+1  A: 
using System.ComponentModel;
using System.Reflection;


public enum ArrowDirection
{

[Description("Northwards")]
North,

[Description("Southwards")]
South,

[Description("Eastwards")]
East,

[Description("Westwards")]
West
}

...

Create an extension method to get a list of descriptions:

public static class Enum<T> where T : struct
{

    /// <summary>
    /// Gets a collection of the enum value descriptions.
    /// </summary>
    /// <returns></returns>
    public static IList<string> GetDescriptions()
    {
        List<string> descriptions = new List<string>();
        foreach (object enumValue in Enum<T>.GetValues())
        {
            descriptions.Add(((Enum)enumValue).ToDescription());
        }
        return descriptions;

    }
}
Mitch Wheat