2009-03-25 2 views
21

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

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

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

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

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

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

ответ

37

В C# 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(); 

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

Here's another example on my blog.

+0

Это довольно круто. Хотя я знал о расширениях, я никогда не думал использовать их для расширения enum. –

+0

Да, я либо поначалу. Об этом рассказал мне друг. Очень мило. Я также был удивлен, узнав (недавно, здесь, на SO), что вы можете вызвать метод расширения по нулевому значению. Он по-прежнему работает, потому что это статический метод. Как обычно, команда C# отлично поработала над этими функциями. –

+0

Вы получите принятый ответ. Я попробовал, и он работает отлично. Единственное. Где именно я должен объявить перечисление? Если я оставлю это в классе, он говорит, что он менее доступен. Мне пришлось создать класс ClassName_Enums, чтобы он работал ... – colithium

3

Об этом сообщается в блоге here.

Попробуйте что-нибудь подобное 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); 

    } 

    } 

Вместо Описание, используйте настраиваемое свойство

0

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

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

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

+0

Я использовал это тоже, и это нравится. Но только недавно я нашел то, что мне нравилось еще больше. Вы можете поместить методы расширения на перечисления! Забавно, сколько удовольствия приносит мне ... но это действительно приятно. –

+0

Я должен проверить это, спасибо за информацию –

0

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

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

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

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

    } 
} 
+0

Это не похоже на метод расширения. Где параметр 'this'? Кроме того, откуда идет «ToDescription»? Предполагается, что это метод расширения? – CoderDennis

Смежные вопросы