2012-06-13 18 views
61

Así que estoy creando un juego en XNA, C# 4.0, y necesito administrar una gran cantidad de PowerUps (que en el código son todos heredados de la clase "PowerUp"), y manejar la administración de back-end de los PowerUps que actualmente tener un enum, PowerupEffectType, con un valor para cada clase secundaria de PowerUp. Eventualmente en el código necesito hacer conversiones de PowerupEffectType al tipo de Powerup (de la clase Type, generalmente alcanzado con typeof([class name])).¿Es posible guardar un Tipo (usando "typeof()") en una enumeración?

Como este es un proyecto grupal, quiero unir cada valor de PowerupEffectType a su clase correspondiente. Escriba lo mejor posible, es decir: no solo espero que mis otros programadores usen declaraciones switch para realizar la conversión manualmente y asegurarse adiciones/expansiones posteriores implican pocos cambios en el menor número posible de lugares. Tengo algunas opciones para esto, y lo mejor que he descubierto hasta ahora es crear enum pseudo-métodos que condensen todo en una única instrucción switch (99% de lo que quiero), gracias a algunos consejos que encontré aquí: http://msdn.microsoft.com/en-us/library/bb383974.aspx

Pero estoy tratando de llevarlo un paso más allá - ¿puedo guardar un Type en un enum? Sé que puede guardar enumeraciones como un tipo específico (enlace: http://msdn.microsoft.com/en-us/library/cc138362.aspx), pero Type no es una de ellas. Las opciones actuales son byte, sbyte, short, ushort, int, uint, long y ulong. ¿Hay alguna manera factible de guardar una conversión a Type en cualquiera de los tipos de datos anteriores y viceversa?

Para que quede claro, esto es lo que me gustaría poder hacer, y estoy buscando una manera de hacerlo:

// (Assuming 'LightningPowerup', 'FirePowerup', and 'WaterPowerup' are 
// all declared classes that inherit from a single base class) 

public enum PowerupEffectType 
{ 
    LIGHTNING = typeof(LightningPowerup), 
    FIRE = typeof(FirePowerup), 
    WATER = typeof(WaterPowerup) 
} 

¿Hay alguna manera de hacer esto, o estoy simplemente ¿complicar demasiado una solución a un problema que ya está completado en un 99%?

¡Gracias de antemano!

+0

no sé lo que estás tratando de lograr aquí como su objetivo final, pero huele a algo que deberías lograr con un método virtual en lugar de encender una enumeración. Normalmente, la razón por la que desea obtener un tipo de una enumeración como lo está haciendo es si la enumeración proviene de una fuente externa, probablemente la base de datos. Pero, en ese caso, probablemente desee que su bloque de conmutadores * ejemplifique * el tipo de encendido en lugar de darle el objeto de clase correspondiente. –

Respuesta

93

Usted no puede hacerlo como el valor de una enumeración, pero se puede especificar en un atributo :

using System; 
using System.Runtime.CompilerServices; 

[AttributeUsage(AttributeTargets.Field)] 
public class EffectTypeAttribute : Attribute 
{ 
    public Type Type { get; private set; } 

    public EffectTypeAttribute(Type type) 
    { 
     this.Type = type; 
    } 
} 

public class LightningPowerup {} 
public class FirePowerup {} 
public class WaterPowerup {} 

public enum PowerupEffectType 
{ 
    [EffectType(typeof(LightningPowerup))] 
    Lightning, 
    [EffectType(typeof(FirePowerup))] 
    Fire, 
    [EffectType(typeof(WaterPowerup))] 
    Water 
} 

A continuación, puede extraer los valores de atributo en tiempo de ejecución con la reflexión . Sin embargo, yo personalmente acaba de crear un diccionario:

private static Dictionary<PowerupEffectType, Type> EffectTypeMapping = 
    new Dictionary<PowerupEffectType, Type> 
{ 
    { PowerupEffectType.Lightning, typeof(LightningPowerup) }, 
    { PowerupEffectType.Fire, typeof(FirePowerup) }, 
    { PowerupEffectType.Water, typeof(WaterPowerup) } 
}; 

No hay necesidad de un atributo especial, sin necesidad de extraer los valores con código de reflexión más incómoda.

+0

Interesante ... tienes razón en que un diccionario definitivamente sería el método más simple, solo estoy buscando aprender algunas técnicas nuevas, así que una solución de complicaciones podría ser exactamente lo que estoy buscando. Dicho esto, no sabía acerca de los atributos, y esto cambia las cosas. ¡Gracias! – KeithA45

+3

"código de reflexión difícil" - Me encanta. :) – Ryan

+0

o crea un diccionario estático en el tiempo de ejecución, se inicializa perezosamente con la reflexión sobre los atributos enum.podría ser lo mejor de ambos mundos –

2

Puede usar solo tipos numéricos como por documentación de Microsoft. Por defecto, el tipo subyacente de cada elemento en la enumeración es int. Puede especificar otro tipo numérico integral usando dos puntos, como se muestra en el ejemplo anterior. Para obtener una lista completa de los posibles tipos, vea enum. Reference: Enumeration Types

9

Puede usar static Dictionary<PowerupEffectType, Powerup>. Creo que ese sería el tipo de "matrimonio" que estás buscando. Permitiría una fácil enumeración y acceso.

16

¿Qué tal algo así?

Usted obtiene la seguridad de tipos que se hace con una enumeración, además de la conversión implícita al tipo

public class PowerupEffectType 
{ 
    private readonly Type _powerupType; 

    public static implicit operator Type(PowerupEffectType powerupEffectType) 
    { 
     return powerupEffectType._powerupType; 
    } 

    private PowerupEffectType(Type powerupType) 
    { 
     _powerupType = powerupType; 
    } 

    public static readonly PowerupEffectType LIGHTNING = new PowerupEffectType(typeof(LightningPowerup)); 
    public static readonly PowerupEffectType FIRE = new PowerupEffectType(typeof(FirePowerup)); 
    public static readonly PowerupEffectType WATER = new PowerupEffectType(typeof(WaterPowerup)); 
} 
+2

Esto definitivamente se acerca más a lo que quiere el OP. Para mayor bondad, la [etiqueta XML doc 'completionlist'] (http://stackoverflow.com/a/102217/1968) se puede usar para proporcionar el auto-completado automático enum para este tipo, pero desafortunadamente solo en VB, no para C#. –

+0

Impresionante! No estoy seguro de usar esto, pero esto ciertamente me enseñó una nueva técnica. ¿Cuál es la sintaxis para sacar el Type del PowerupEffectType? ¿Puedes dar un ejemplo de código rápido? – KeithA45

+3

Solo publíquelo en "Tipo" (Tipo) PowerupEffectType.FIRE – mlorbetske

18

Esto no es exactamente lo que u está pidiendo. Creo que el método de atributos de Jon es el mejor. Pero, ¿por qué no envolverlo en un método de extensión?

public Type GetPowerupEffectType(this PowerupEffectType powerEffect) 
{ 
    switch (powerEffect) 
    { 
     case LIGHTNING: 
      return typeof(LightningPowerup); 
     case FIRE: 
      return typeof(FirePowerup); 
     case WATER: 
      return typeof(WaterPowerup); 
     default: 
      return default(Type); 
    } 
} 

y llamarlo:

PowerupEffectType e = PowerupEffectType.WATER; 
var t = e.GetPowerupEffectType(); 
+0

Eso es más o menos lo que hago ahora, con la excepción de que de manera predeterminada establece "Lanzar nueva NotImplementedException()", para asegurarse de que si mis otros desarrolladores agregan una enumeración, también tienen que agregarlo a la declaración de cambio de extensión. Es el 99% de lo que quiero, solo estoy buscando técnicas para incorporarlo a la declaración enum. Aún así, ¡gracias! – KeithA45

+1

@ KeithA45 Sí Keith, eso es correcto. Por eso digo que el primer método de Jon es el mejor que encontré. – nawfal

2

Lo sentimos, no comprendo muy bien esto, ¿qué estás realmente tratando de lograr; podrías dar un extracto del código? No estoy seguro de por qué no puede usar herencia aquí y lo que una enumeración le da a ese tipo de herencia no lo hace. Me parece que estás presentando la solución más que el problema, puedo estar completamente equivocado, ¿podrías aclarar cómo planeas utilizar esta metainformación?

Estoy confundido, ¿estás pidiendo algo que te indique el tipo de instancia de un tipo/clase? Puede usar una enumeración para almacenar una lista de los tipos de cada tipo que dice, pero ¿por qué quiere? Usted dice que no quiere que los otros programadores usen declaraciones de cambio, pero lamento no poder ver qué beneficio obtiene almacenando la información de tipo en alguna enumeración de ... el tipo. Cada instancia sabe de qué tipo es y qué puede hacer.

¿Qué vas a hacer con la información del tipo? Si todos los tipos heredan de un tipo base, presumiblemente tienen una funcionalidad común que se puede especificar en un método abstract para cualquier manejo de casos especiales, o tal vez devolver un Null Object donde no hay nada que hacer (o simplemente no hacer nada). De esta forma, no tendrá que preocuparse por agregar nuevas clases, ya que deben tener el comportamiento necesario. Intento evitar Enum s, excepto en situaciones en las que en realidad se está enumerando un conjunto fijo de valores arbitrarios, son inflexibles. Enum s tienen que mantenerse, lo cual es muy difícil (en la práctica).

Cuestiones relacionadas