简体   繁体   中英

What is the efficient way to store and read additional information from enums

I was trying to store and retrieve additional information from enums. I ended up with 2 methods for it. The first method is by using custom attributes. https://stackoverflow.com/a/22054994/5078531 https://stackoverflow.com/a/35040378/5078531

public class DayAttribute : Attribute
{
    public string Name { get; private set; }

    public DayAttribute(string name)
    {
        this.Name = name;
    }
}

enum Days
{
    [Day("Saturday")]
    Sat,
    [Day("Sunday")]
    Sun
}

public static TAttribute GetAttribute<TAttribute>(this Enum value)
        where TAttribute : Attribute
    {
        var enumType = value.GetType();
        var name = Enum.GetName(enumType, value);
        return enumType.GetField(name).GetCustomAttributes(false).OfType<TAttribute>().SingleOrDefault();
    }

The second method I found here, by writing an extension method on enums. https://stackoverflow.com/a/680515/5078531

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

public static class ArrowDirectionExtensions
{
     public static UnitVector UnitVector(this ArrowDirection self)
     {         
         switch(self)
         {
             case ArrowDirection.North:
                 return new UnitVector(0, 1);
             case ArrowDirection.South:
                 return new UnitVector(0, -1);
             case ArrowDirection.East:
                 return new UnitVector(1, 0);
             case ArrowDirection.West:
                 return new UnitVector(-1, 0);
             default:
                 return null;
         }
     }
}

If am looking for the performance which method should I choose ? or is there any other efficient methods which am missing?

Both are valid ways of implementing it; as are many other ways. Personally, I like the convenience of the first. The performance penalty of reflection can be mitigated by processing the attributes once only, and storing (presumably in a static field) - potentially as a flat array if the enum values are contiguous and 0-based; otherwise, perhaps in a dictionary.

You can make DayaAttributeCache more generic if you like such that it can store other enum and attribute types. I just did this quick to show a caching approach. Enum values have to be continuous starting at 0 but this can be changed to handle that case if needed.

public static class DaysAttributeCache
{
    private static readonly string[] Cache;

    static DaysAttributeCache()
    {
        Type enumType = typeof(Days);
        Cache = new string[Enum.GetValues(enumType).Length];

        foreach (Enum value in Enum.GetValues(enumType))
        {
          var name = Days.GetName(enumType, value);

          DayAttribute attribute = enumType
              .GetField(name)
              .GetCustomAttributes(false)
              .OfType<DayAttribute>()
              .SingleOrDefault();

          string weekDay = attribute?.Name;
          Cache[((IConvertible)value).ToInt32(CultureInfo.InvariantCulture)] = weekDay;
        }
    }

    public static string GetWeekday(this Days value)
    {
        return Cache[(int)value];
    }
  }

Called like this...

string saturday = Days.Sat.GetWeekday();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM