2009-11-30 19 views
80

tengo una enumeración de, por ejemplo 'Gender' (Male =0 , Female =1) y tengo otra enumeración de un servicio que tiene su propia enumeración de Género (Male =0 , Female =1, Unknown =2)convertir una enumeración a otro tipo de enumeración

Mi pregunta es ¿cómo puede Escribo algo rápido y agradable para convertir de su enum al mío.

+4

¿A qué desea convertir "desconocido"? –

+0

Puede encasillar la enumeración en otros tipos de enumeración cuando ambos tienen los mismos valores, véase http://ideone.com/7lgvgf –

Respuesta

63

utilizando un método de extensión de las obras muy claramente, cuando se utilizan los dos métodos de conversión sugeridas por Nate:

public static class TheirGenderExtensions 
{ 
    public static MyGender ToMyGender(this TheirGender value) 
    { 
     // insert switch statement here 
    } 
} 

public static class MyGenderExtensions 
{ 
    public static TheirGender ToTheirGender(this MyGender value) 
    { 
     // insert switch statement here 
    } 
} 

Obviamente no hay necesidad de usar clases separadas si no quiere. Mi preferencia es mantener los métodos de extensión agrupados por las clases/estructuras/enumeraciones a las que se aplican.

20

Para ser minucioso, normalmente creo un par de funciones, una que toma Enum 1 y devuelve Enum 2 y otra que toma Enum 2 y devuelve Enum 1. Cada una consiste en una entrada de asignación de mayúsculas y minúsculas a las salidas y el caso predeterminado una excepción con un mensaje quejándose de un valor inesperado.

En este caso en particular, podría aprovechar el hecho de que los valores enteros de Hombre y Mujer son los mismos, pero evitaría eso ya que es hackish y está sujeto a rotura si cualquiera de las enum cambia en el futuro.

+7

+1. He visto a muchos desarrolladores ceder a la tentación de usar valores enteros de enumeraciones para convertirlos, pero esto es muy propenso a errores El método de la escuela anterior de escribir 2 funciones ha demostrado su valía en el tiempo ... – Hemant

130

Dado Enum1 value = ..., a continuación, si usted quiere decir por su nombre:

Enum2 value2 = (Enum2) Enum.Parse(typeof(Enum2), value.ToString()); 

Si quieres decir con valor numérico, por lo general puede simplemente fundido:

Enum2 value2 = (Enum2)value; 

(con el elenco, es posible que desee use Enum.IsDefined para verificar valores válidos)

+4

Esta es la mejor respuesta – Nicholas

0

Puede usar ToString() para convertir la primera enumeración en su nombre, y luego Enum.Parse() para convertir la cadena de nuevo al otro Enum. Esto producirá una excepción si el valor no es compatible con la enumeración de destino (es decir, para un valor "desconocido")

6

se podría escribir una función simple como la siguiente:

public static MyGender ConvertTo(TheirGender theirGender) 
{ 
    switch(theirGender) 
    { 
     case TheirGender.Male: 
      break;//return male 
     case TheirGender.Female: 
      break;//return female 
     case TheirGender.Unknown: 
      break;//return whatever 
    } 
} 
37

Sólo lanzar uno a int y luego echarlo a la otra enumeración (teniendo en cuenta que desea que el mapeo realiza con base en el valor):

Gender2 gender2 = (Gender2)((int)gender1); 
+2

Aunque es poco probable que sea "salvaje", y es muy poco probable que sea el caso para los géneros, podría haber existe alguna enumeración respaldada por un 'long' (o' ulong') en lugar de un 'int' que tiene miembros definidos que están por encima de' int.MaxValue' (o por debajo de 'int.MinValue'), en cuyo caso el molde a 'int' podría desbordarse y terminaría con un valor de enum indefinido que debería definirse. –

+0

por supuesto. la forma correcta sería (Gender2) ((inserte el tipo subyacente aquí) gender1) pero creo que el ejemplo anterior da la idea correcta, así que no la cambiaré. –

+2

Esto requiere que las dos enumeraciones tengan los mismos valores en el mismo orden. Si bien resuelve este problema específico, esto es realmente frágil y no utilizaría esto para el mapeo enum en general. – sonicblis

12

Se puede escribir un simple método de extensión genérica como esta

public static T ConvertTo<T>(this object value)    
    where T : struct,IConvertible 
{ 
    var sourceType = value.GetType(); 
    if (!sourceType.IsEnum) 
     throw new ArgumentException("Source type is not enum"); 
    if (!typeof(T).IsEnum) 
     throw new ArgumentException("Destination type is not enum"); 
    return (T)Enum.Parse(typeof(T), value.ToString()); 
} 
1

Escribí un conjunto de métodos de extensión un tiempo atrás que funcionan para varios tipos diferentes de Enum s. Uno en particular funciona para lo que está tratando de lograr y maneja Enum s con FlagsAttribute y Enum s con diferentes tipos subyacentes.

public static tEnum SetFlags<tEnum>(this Enum e, tEnum flags, bool set, bool typeCheck = true) where tEnum : IComparable 
{ 
    if (typeCheck) 
    { 
     if (e.GetType() != flags.GetType()) 
      throw new ArgumentException("Argument is not the same type as this instance.", "flags"); 
    } 

    var flagsUnderlyingType = Enum.GetUnderlyingType(typeof(tEnum)); 

    var firstNum = Convert.ToUInt32(e); 
    var secondNum = Convert.ToUInt32(flags); 

    if (set) 
     firstNum |= secondNum; 

    else 
     firstNum &= ~secondNum; 

    var newValue = (tEnum)Convert.ChangeType(firstNum, flagsUnderlyingType); 

    if (!typeCheck) 
    { 
     var values = Enum.GetValues(typeof(tEnum)); 
     var lastValue = (tEnum)values.GetValue(values.Length - 1); 

     if (newValue.CompareTo(lastValue) > 0) 
      return lastValue; 
    } 

    return newValue; 
} 

Desde allí puede agregar otros métodos de extensión más específicos.

public static tEnum AddFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable 
{ 
    SetFlags(e, flags, true); 
} 

public static tEnum RemoveFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable 
{ 
    SetFlags(e, flags, false); 
} 

Ésta cambiará tipos de Enum s como si estuviera tratando de hacer.

public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable 
{ 
    return SetFlags(e, default(tEnum), true, false); 
} 

Se advirtió, sin embargo, que se puede convertir entre cualquier EnumEnum y cualquier otro uso de este método, incluso aquellos que no tienen banderas. Por ejemplo:

public enum Turtle 
{ 
    None = 0, 
    Pink, 
    Green, 
    Blue, 
    Black, 
    Yellow 
} 

[Flags] 
public enum WriteAccess : short 
{ 
    None = 0, 
    Read = 1, 
    Write = 2, 
    ReadWrite = 3 
} 

static void Main(string[] args) 
{ 
    WriteAccess access = WriteAccess.ReadWrite; 
    Turtle turtle = access.ChangeType<Turtle>(); 
} 

La variable turtle tendrá un valor de Turtle.Blue.

Sin embargo, existe la seguridad de los valores Enum indefinidos utilizando este método. Por ejemplo:

static void Main(string[] args) 
{ 
    Turtle turtle = Turtle.Yellow; 
    WriteAccess access = turtle.ChangeType<WriteAccess>(); 
} 

En este caso, access se establecerá en WriteAccess.ReadWrite, ya que el WriteAccessEnum tiene un valor máximo de 3.

Otro efecto secundario de la mezcla de Enum s con el FlagsAttribute y los que no lo es que el proceso de conversión no dará como resultado una coincidencia de 1 a 1 entre sus valores.

public enum Letters 
{ 
    None = 0, 
    A, 
    B, 
    C, 
    D, 
    E, 
    F, 
    G, 
    H 
} 

[Flags] 
public enum Flavors 
{ 
    None = 0, 
    Cherry = 1, 
    Grape = 2, 
    Orange = 4, 
    Peach = 8 
} 

static void Main(string[] args) 
{ 
    Flavors flavors = Flavors.Peach; 
    Letters letters = flavors.ChangeType<Letters>(); 
} 

En este caso, letters tendrá un valor de Letters.H en lugar de Letters.D, ya que el valor de soporte de Flavors.Peach es de 8. También, una conversión de Flavors.Cherry | Flavors.Grape a Letters produciría Letters.C, que puede parecer poco intuitivo.

3

He aquí una versión método de extensión si alguien está interesado

public static TEnum ConvertEnum<TEnum >(this Enum source) 
    { 
     return (TEnum)Enum.Parse(typeof(TEnum), source.ToString(), true); 
    } 

// Usage 
NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>(); 
+0

¿No implica eso que ambas enumeraciones tienen los mismos valores numéricos? – kuskmen

+0

No, esto es convertir por nombre por cadena. Entonces Enum.Foo (1) se traducirá a Enum2.Foo (2) aunque sus valores numéricos sean diferentes. – Justin

8

Si tenemos:

enum Gender 
{ 
    M = 0, 
    F = 1, 
    U = 2 
} 

y

enum Gender2 
{ 
    Male = 0, 
    Female = 1, 
    Unknown = 2 
} 

que podemos hacer de manera segura

var gender = Gender.M; 
var gender2 = (Gender2)(int)gender; 

O incluso

var enumOfGender2Type = (Gender2)0; 

Si desea cubrir el caso en que una enumeración en el lado derecho de la señal de '=' tiene más valores que la enumeración en el lado izquierdo - usted tendrá que escribir su propio método/diccionario para cubrir eso como otros sugirieron.

+0

¡Su respuesta es como hacer una pregunta !? En caso afirmativo, esta no es una respuesta y, en caso negativo, hay una [respuesta similar arriba] (http://stackoverflow.com/a/1818786/4519059);). –

0

sé que es una cuestión de edad y tienen una gran cantidad de respuestas, sin embargo me parece que el uso de una sentencia switch como en la respuesta aceptada es algo engorroso, así que aquí están mis 2 centavos:

Mi método favorito es usar un diccionario, donde la clave es la enumeración de origen y el valor es la enumeración de destino - por lo que en el caso presentado sobre la cuestión mi código sería el siguiente:

var genderTranslator = new Dictionary<TheirGender, MyGender>(); 
genderTranslator.Add(TheirGender.Male, MyGender.Male); 
genderTranslator.Add(TheirGender.Female, MyGender.Female); 
genderTranslator.Add(TheirGender.Unknown, MyGender.Unknown); 

// translate their to mine  
var myValue = genderTranslator[TheirValue]; 

// translate mine to their 
var TheirValue = genderTranslator .FirstOrDefault(x => x.Value == myValue).Key;; 

por supuesto, esto puede ser envuelto en una clase estática y se utilizará como métodos de extensión:

public static class EnumTranslator 
{ 

    private static Dictionary<TheirGender, MyGender> GenderTranslator = InitializeGenderTranslator(); 

    private static Dictionary<TheirGender, MyGender> InitializeGenderTranslator() 
    { 
     var translator = new Dictionary<TheirGender, MyGender>(); 
     translator.Add(TheirGender.Male, MyGender.Male); 
     translator.Add(TheirGender.Female, MyGender.Female); 
     translator.Add(TheirGender.Unknown, MyGender.Unknown); 
     return translator; 
    } 

    public static MyGender Translate(this TheirGender theirValue) 
    { 
     return GenderTranslator[theirValue]; 
    } 

    public static TheirGender Translate(this MyGender myValue) 
    { 
     return GenderTranslator.FirstOrDefault(x => x.Value == myValue).Key; 
    } 

}