2009-05-26 18 views
80

Mi piacerebbe creare un metodo generico per convertire qualsiasi tipo di System.Enum derivato al suo valore intero corrispondente, senza eseguire il cast e preferibilmente senza analizzare una stringa.Come convertire da System.Enum in numero intero di base?

Ad esempio, quello che voglio è qualcosa di simile:

// Trivial example, not actually what I'm doing. 
class Converter 
{ 
    int ToInteger(System.Enum anEnum) 
    { 
     (int)anEnum; 
    } 
} 

Ma questo non sembra funzionare. Resharper segnala che non puoi trasmettere espressioni di tipo 'System.Enum' per digitare 'int'.

Ora ho trovato questa soluzione ma preferirei avere qualcosa di più efficiente.

class Converter 
{ 
    int ToInteger(System.Enum anEnum) 
    { 
     return int.Parse(anEnum.ToString("d")); 
    } 
} 

Qualche suggerimento?

+1

Credo che sia il compilatore a lamentarsi, non a Resharper. – Kugel

+1

Non necessariamente. Ho un metodo di estensione su System.Enum, e occasionalmente Resharper decide di lamentarsi: Impossibile convertire l'argomento dell'istanza tipo 'Some.Cool.Type.That.Is.An.Enum' a 'System.Enum' quando è indiscutibilmente È un enum. Se compilo ed eseguo il codice funziona perfettamente. Se poi chiudo VS, soffio via la cache di Resharper e la riaccendi, tutto va bene una volta eseguita la scansione. Per me è una specie di cache snafu. Potrebbe essere lo stesso per lui. – Mir

+0

@Mir Ho avuto ReSharper "lamentarsi" anche di questo. Stessa correzione per me. Non sono sicuro del motivo per cui questi tipi vengono mescolati, ma non è sicuramente il compilatore. – akousmata

risposta

114

Se non si vuole lanciare,

Convert.ToInt32() 

potrebbe fare il trucco.

Il cast diretto (tramite (int)enumValue) non è possibile. Si noti che questo sarebbe anche "pericoloso" poiché un enum può avere diversi tipi di sottostanti (int, long, byte ...).

Più formalmente: System.Enum non ha alcuna relazione diretta eredità con Int32 (anche se entrambi sono ValueType s), in modo che il cast esplicito non può essere corretto all'interno del sistema di tipo

+2

'Convertitore.ToInteger (MyEnum.MyEnumConstant);' non ti darà alcun errore qui. Si prega di modificare quella parte. – nawfal

+0

Grazie, @nawfal, hai ragione. Ho modificato la risposta (e ho imparato qualcosa di nuovo :) ...) – MartinStettner

+0

Non funziona se il tipo sottostante differisce da 'int' –

1

La trasmissione da System.Enum a int funziona correttamente (è anche su MSDN). Forse è un bug di Resharper.

+1

Quale versione del runtime si sta utilizzando? – JoshBerke

+2

il collegamento mostra la trasmissione di sottotipi di 'System.Enum', non' System.Enum' stesso. – nawfal

+0

Un problema simile che ho avuto è stato un snaku cache di Resharper. La chiusura di VS e l'eliminazione della cache di Resharper hanno fatto scomparire l'errore, anche dopo una completa scansione. – Mir

34

ho preso a lavorare per colata a un oggetto e poi to int:

public static class EnumExtensions 
{ 
    public static int ToInt(this Enum enumValue) 
    { 
     return (int)((object)enumValue); 
    } 
} 

Questo è brutto e probabilmente non è il modo migliore. Continuerò a scherzare, per vedere se riesco a inventarmi qualcosa di meglio ...

EDIT: stavo per pubblicare anche Convert.ToInt32 (enumValue) e ho notato che MartinStettner mi ha battuto ad esso.

public static class EnumExtensions 
{ 
    public static int ToInt(this Enum enumValue) 
    { 
     return Convert.ToInt32(enumValue); 
    } 
} 

prova:

int x = DayOfWeek.Friday.ToInt(); 
Console.WriteLine(x); // results in 5 which is int value of Friday 

EDIT 2: Nei commenti, qualcuno ha detto che questo funziona solo in C# 3.0. Ho appena provato questo in VS2005 come questo e ha funzionato:

public static class Helpers 
{ 
    public static int ToInt(Enum enumValue) 
    { 
     return Convert.ToInt32(enumValue); 
    } 
} 

    static void Main(string[] args) 
    { 
     Console.WriteLine(Helpers.ToInt(DayOfWeek.Friday)); 
    } 
+0

Ti ho dato +1 ma questa soluzione funzionerà solo con C# 3.0 e versioni successive. – Vadim

+0

Penso che questo soddisfi solo il compilatore. Sei riuscito a testare questo in fase di runtime? Non è stato possibile passare alcun valore a questa funzione ... – MartinStettner

+0

Perché è un metodo di estensione? O c'è qualcosa di diverso nell'enumerazione nelle vecchie versioni di C#? – BFree

-1

non dimenticare che il tipo Enum in sé ha un sacco di funzioni di supporto statiche in esso. Se tutto ciò che si vuole fare è convertire un'istanza dell'enum nel suo tipo intero corrispondente, quindi il casting è probabilmente il modo più efficace.

Penso che ReSharper si stia lamentando perché Enum non è un'enumerazione di alcun tipo particolare e le enumerazioni derivano da un valore di tipo scalare, non Enum.Se avete bisogno di colata adattabili in modo generico, direi che questo potrebbe Suite È bene (notare che il tipo di enumerazione in sé è anche incluso nel generico:

public static EnumHelpers 
{ 
    public static T Convert<T, E>(E enumValue) 
    { 
     return (T)enumValue; 
    } 
} 

Questo potrebbe quindi essere utilizzato in questo modo:

public enum StopLight: int 
{ 
    Red = 1, 
    Yellow = 2, 
    Green = 3 
} 

// ... 

int myStoplightColor = EnumHelpers.Convert<int, StopLight>(StopLight.Red); 

non posso dire per certo fuori dalla parte superiore della mia testa, ma il codice di cui sopra potrebbe anche essere supportata da inferenza di tipo C# 's, permettendo la seguente:

int myStoplightColor = EnumHelpers.Convert<int>(StopLight.Red); 
+1

Sfortunatamente, nel tuo esempio E può essere qualsiasi tipo. Generics non mi permette di usare Enum come tipo di vincolo del parametro. Non posso dire: dove T: Enum – Vadim

+0

Si può usare dove T: struct, però. Non è così rigoroso come vuoi, ma eliminerebbe qualsiasi tipo di riferimento (che credo sia quello che stai cercando di fare). – jrista

+0

puoi usare: se (! Typeof (E) .IsEnum) lanciare nuovi ArgumentException ("E deve essere un tipo enumerato"); – diadiora

11

Perché avete bisogno di reinventare ° e ruota con un metodo di supporto? È perfettamente legale trasmettere un valore enum al tipo sottostante.

E 'meno di battitura, e, a mio parere più leggibile, da usare ...

int x = (int)DayOfWeek.Tuesday; 

... piuttosto che qualcosa di simile ...

int y = Converter.ToInteger(DayOfWeek.Tuesday); 
// or 
int z = DayOfWeek.Tuesday.ToInteger(); 
+4

Voglio convertire QUALSIASI valore enum. Vale a dire, ho una varietà di classi che hanno campi enum che vengono elaborati da un certo codice in un modo generico. Questo è il motivo per cui un cast semplice per int non è appropriato. – orj

+0

@orj, non sono proprio sicuro di cosa intendi. Puoi fare un esempio che mostri l'utilizzo di cui hai bisogno? – LukeH

+2

A volte non è possibile eseguire direttamente un'enumerazione, come nel caso di un metodo generico. Poiché i metodi generici non possono essere vincolati a enumerazioni, è necessario limitarli a qualcosa come struct, che non può essere convertito in un int. In tal caso, puoi usare Convert.ToInt32 (enum) per farlo. –

4

Dalla mia risposta here:

Dato e come in:

Enum e = Question.Role; 

Poi questi lavori:

int i = Convert.ToInt32(e); 
int i = (int)(object)e; 
int i = (int)Enum.Parse(e.GetType(), e.ToString()); 
int i = (int)Enum.ToObject(e.GetType(), e); 

Gli ultimi due sono semplicemente brutto. Il primo dovrebbe essere più leggibile, anche se il secondo è molto più veloce. O potrebbe essere un metodo di estensione è il migliore, il meglio di entrambi i mondi.

public static int GetIntValue(this Enum e) 
{ 
    return e.GetValue<int>(); 
} 

public static T GetValue<T>(this Enum e) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T> 
{ 
    return (T)(object)e; 
} 

Ora è possibile chiamare:

e.GetValue<int>(); //or 
e.GetIntValue(); 
+0

Sei sicuro che il secondo è più veloce? Presumo che chiuderà l'enum e poi unbox di nuovo a int? – yoyo

+1

@yoyo la variabile 'e' contiene già l'istanza in box del tipo di valore effettivo, ad esempio enum. Quando scrivi 'Enum e = Question.Role;' è già in scatola. La domanda riguarda la conversione di "System.Enum" in box al tipo int sottostante (unboxing). Quindi qui l'unboxing è solo la preoccupazione per le prestazioni. '(int) (object) e' è una chiamata di unbox diretta; sì dovrebbe essere più veloce di altri approcci. [Vedi questo] (http://stackoverflow.com/questions/7995606/boxing-occurrence-in-c-sharp) – nawfal

+0

grazie per la spiegazione. Avevo l'impressione errata che un'istanza di System.Enum fosse un valore non condiviso. Vedi anche questo - http://msdn.microsoft.com/en-us/library/aa691158(v=vs.71).aspx – yoyo

8

Se avete bisogno di convertire qualsiasi enum al tipo di fondo (non tutte le enumerazioni sono supportate da int) allora si può usare:

return System.Convert.ChangeType(
    enumValue, 
    Enum.GetUnderlyingType(enumValue.GetType())); 
+4

Questa è l'unica risposta a prova di proiettile. –

+0

Questa dovrebbe essere la risposta accettata. –

Problemi correlati