Подтвердить что ты не робот

Связывание дополнительной информации с .NET Enum

Мой вопрос лучше всего иллюстрируется примером.

Предположим, что у меня есть перечисление:

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

Я хочу связать единичный вектор, соответствующий каждому направлению с этим направлением. Например, я хочу что-то, что вернет (0, 1) для North, (-1, 0) для West и т.д. Я знаю, что в Java вы можете объявить метод внутри перечисления, который мог бы обеспечить эту функциональность.

Мое текущее решение - иметь статический метод - внутри класса, который определяет перечисление, - который возвращает вектор, соответствующий переданному в ArrowDirection (метод использует HashTable для выполнения поиска, но это не очень важно). Это кажется... нечистым.

Вопрос:
Есть ли лучшее решение для хранения дополнительной информации, соответствующей перечислению в .NET?

4b9b3361

Ответ 1

В С# 3.0 появился новый способ FANTASTIC. Ключом является этот красивый факт: у Enums могут быть методы расширения! Итак, вот что вы можете сделать:

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
         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;
         }
     }
}

Теперь вы можете сделать это:

var unitVector = ArrowDirection.North.UnitVector();

Сладкое! Я только узнал об этом месяц назад, но это очень хорошее следствие новых возможностей С# 3.0.

Вот еще один пример моего блога.

Ответ 2

Я писал об этом здесь.

Попробуйте что-то подобное с помощью Атрибуты.

  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);

    }

  }

Вместо описания используйте свое пользовательское свойство

Ответ 3

using System.ComponentModel;
using System.Reflection;


public enum ArrowDirection
{

[Description("Northwards")]
North,

[Description("Southwards")]
South,

[Description("Eastwards")]
East,

[Description("Westwards")]
West
}

...

Создайте метод расширения, чтобы получить список описаний:

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;

    }
}

Ответ 4

Одна вещь, на которую вы могли бы обратить внимание, - это шаблон "Тип-безопасный переход". Это позволяет создать перечисление, которое на самом деле является полноценным статическим объектом, который может иметь методы/свойства/и т.д.

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

Джошуа Блох рассказывает об этом шаблоне в своей книге "Эффективная Ява". Я использовал его во многих разных ситуациях, и я предпочитаю его на простых перечислениях. (Это язык-агностик - он работает на Java, С# или почти любом языке OO).

Ответ 5

Ваш подход к статическому методу кажется мне совершенно чистым. Вы инкапсулируете как перечисление, так и статический метод в один класс. Изменения в перечислении централизованы внутри этого единственного класса.

Добавление метода к перечислению (в соответствии с Java), похоже, добавляет сложности к чему-то, что действительно очень простое понятие.

Подход, основанный на атрибутах, интересен, но в очередной раз кажется, что он перегружает вещи по сравнению со статическим методом.