2009-03-25 18 views
21

Mi pregunta se ilustra mejor con un ejemplo.Asociación de información adicional con .NET Enum

Supongamos que tengo la enumeración:

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

que desea asociar el vector unitario correspondiente a cada dirección con esa dirección. Por ejemplo, quiero algo que retorne (0, 1) para Norte, (-1, 0) para Oeste, etc. Sé que en Java podrías declarar un método dentro de la enumeración que podría proporcionar esa funcionalidad.

Mi solución actual es tener un método estático, dentro de la clase que define la enumeración, que devuelve un vector correspondiente a la pasada en ArrowDirection (el método usa una HashTable para realizar la búsqueda, pero eso no es realmente importante) . Esto parece ... sucio.

Pregunta:
¿Existe una solución de mejores prácticas para almacenar información adicional correspondiente a una enumeración en .NET?

Respuesta

37

Hay una FANTÁSTICA nueva forma de hacer esto en C# 3.0. La clave es este hermoso hecho: ¡los mensajes pueden tener métodos de extensión! Por lo tanto, esto es lo que puede hacer:

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

Ahora, usted puede hacer esto:

var unitVector = ArrowDirection.North.UnitVector(); 

dulce! Solo descubrí esto hace aproximadamente un mes, pero es una buena consecuencia de las nuevas características de C# 3.0.

Here's another example on my blog.

+0

Eso es genial. Aunque sabía sobre extensiones, nunca pensé usarlas para la extensión enum –

+0

Sí, yo tampoco al principio. Un amigo me lo contó. Es muy bonito. También me sorprendió saber (recientemente, aquí en SO) que puede llamar a un método de extensión con un valor nulo. Todavía funciona porque es un método estático. Como de costumbre, el equipo de C# ha hecho un gran trabajo pensando en estas características. –

+0

Obtendrá la respuesta aceptada. Lo intenté y funciona perfectamente. La unica cosa es. ¿Dónde exactamente debería declarar la enumeración? Si lo dejo en la clase, dice que es menos accesible. Tuve que crear una clase "ClassName_Enums" para que funcione ... – colithium

3

He escrito sobre él here.

Pruebe algo como esto con 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); 

    } 

    } 

En lugar de Descripción, utilice su propiedad personalizada

0

Una cosa que podría tener en cuenta es el patrón "con seguridad de tipos Enum". Esto le permite crear una enumeración que en realidad es un objeto estático de pleno derecho, que puede tener métodos/propiedades/etc ..

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

Joshua Bloch habla de este patrón en su libro "Effective Java." Lo he usado en muchas situaciones diferentes, y en realidad lo prefiero en lugar de enumeraciones simples. (Es independiente del lenguaje, funciona en Java, C# o casi cualquier lenguaje OO).

+0

lo he usado demasiado y me gusta. Pero solo recientemente he encontrado algo que me gusta aún más. ¡Puedes poner métodos de extensión en enumeraciones! Es curioso cuánto disfrute que me trae ... pero es realmente agradable. –

+0

Tendré que verificarlo, gracias por la información –

0

Su enfoque de método estático me parece bastante limpio. Encapsula tanto el enum como el método estático dentro de la misma clase. Los cambios en la enumeración se centralizan dentro de esa clase única.

Agregar un método a la enumeración (según Java) parece agregar complejidad a algo que es realmente un concepto muy simple.

El enfoque basado en atributos es interesante, pero una vez más parece complicar las cosas en comparación con un método estático.

1
using System.ComponentModel; 
using System.Reflection; 


public enum ArrowDirection 
{ 

[Description("Northwards")] 
North, 

[Description("Southwards")] 
South, 

[Description("Eastwards")] 
East, 

[Description("Westwards")] 
West 
} 

...

Crear un método de extensión para obtener una lista de las descripciones:

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

Eso no parece un método de extensión. ¿Dónde está el parámetro 'this'? Además, ¿de dónde viene 'ToDescription'? Se supone que es el método de extensión? – CoderDennis

Cuestiones relacionadas