2010-11-04 13 views
7

Sono sicuro che questo è abbastanza banale ma non riesco a farlo bene.Imposta un enum al valore predefinito

public static string DoSomething(this Enum value) 
{ 
    if (!Enum.IsDefined(value.GetType(), value)) 
    { 
     // not a valid value, assume default value 
     value = default(value.GetType()); 
    } 

    // ... do some other stuff 
} 

La linea value = default(value.GetType()); non si compila, ma spero che si può vedere quello che sto cercando. Devo impostare il parametro Enum sul valore predefinito del proprio tipo.

+0

Come può si chiama anche questo metodo senza che il 'valore' sia definito nell'enumerazione dello stesso tipo di 'valore'? –

+0

@Paw, questo è il modo in cui enum funziona. È possibile memorizzare qualsiasi valore int in un int enum, che sia definito o meno. – fearofawhackplanet

+0

@fearofawhackplanet, sto solo cercando di capire cosa stai cercando di fare. Se vuoi convertire un int in un enum o magari una stringa in un enum? –

risposta

1

Activator.CreateInstance(typeof(ConsoleColor)) sembra funzionare

+0

Hai bisogno di un cast duro per questo. (ConsoleColor) Activator.CreateInstance (typeof (ConsoleColor)) –

+0

@Paw, come lo faresti nell'esempio di paura (con un tipo dinamico) –

+0

non puoi, ecco perché non penso che funzionerà con Activator. –

-1

Enum di default hanno il suo first value come default value

+3

di nuovo, in che modo questo risolve il mio problema? (e non è nemmeno tecnicamente corretto non credo) – fearofawhackplanet

+2

-1: Scusa, ma il valore predefinito per ogni enumerazione è 0, anche se 0 è un valore non valido per l'enumerazione. Prova 'enum MyEnum {M1 = -1, M2 = 1}; MyEnum e = default (MyEnum); ... Console.WriteLine ("{0}", e); 'Scritta' 0' –

-1

Avete pensato di fare è un metodo generico?

public static string DoSomething<T>(Enum value) 
{ 
    if (!Enum.IsDefined(typeof(T), value)) 
    { 
     value = (T)Enum.ToObject(typeof(T), 0); 
    } 
    // ... do some other stuff 
} 

Il chiamante del metodo deve conoscere il tipo.

+3

Il 'dove T: enum' non esiste in C#. :-(Questo è l'intero problema qui. –

+0

Ah vero, rimosso quello. –

+0

Funzionerebbe comunque, senza il "dove". Avresti solo bisogno di provare/prendere per assicurarti che il tuo cast non esploda. lanciare una nuova eccezione al chiamante se T non era un enum –

5

Io non sono davvero sicuro di quello che stai cercando di fare qui, ma una versione della linea di 'default' che fa la compilazione è questo:

value = (Enum)Enum.GetValues(value.GetType()).GetValue(0); 

Oppure, ancora più pulito (da Paw, in i commenti, grazie):

value = (Enum) Enum.ToObject(value.GetType(), 0); 

Questa seconda versione funziona correttamente solo se si conosce primo elemento del enum ha un valore pari a zero.

+0

o value = (Enum) Enum.ToObject (value.GetType(), 0); –

+0

@paw E se tu? usando questo: 'enum Foo {a = 1, b = 2}'? +1 a Will, sembra piuttosto robusto –

+0

@Paw: No. 0 non è un valore definito per tutte le enumerazioni –

2

In realtà si potrebbe fare quello che Paw is suggesting, anche con un vincolo generico, se si potesse spostare questo metodo per la propria classe:

public abstract class Helper<T> 
{ 
    public static string DoSomething<TEnum>(TEnum value) where TEnum: struct, T 
    { 
     if (!Enum.IsDefined(typeof(TEnum), value)) 
     { 
      value = default(TEnum); 
     } 

     // ... do some other stuff 

     // just to get code to compile 
     return value.ToString(); 
    } 
} 

public class EnumHelper : Helper<Enum> { } 

Poi si farebbe, ad esempio:

MyEnum x = MyEnum.SomeValue; 
MyEnum y = (MyEnum)100; // Let's say this is undefined. 

EnumHelper.DoSomething(x); // generic type of MyEnum can be inferred 
EnumHelper.DoSomething(y); // same here 

Come Konrad Rudolph fa notare in un commento, default(TEnum) nel codice precedente valuterà a 0, indipendentemente dal fatto che un valore sia definito o uguale a 0 per il tipo dato TEnum. Se questo non è ciò che desideri, lo Will's answer fornisce sicuramente il modo più semplice per ottenere il primo valore definito ((TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0)).

D'altra parte, se si vuole prendere questo al estrema, e memorizzare nella cache il risultato in modo che non si ha sempre a scatola, si potrebbe fare questo:

public abstract class Helper<T> 
{ 
    static Dictionary<Type, T> s_defaults = new Dictionary<Type, T>(); 

    public static string DoSomething<TEnum>(TEnum value) where TEnum: struct, T 
    { 
     if (!Enum.IsDefined(typeof(TEnum), value)) 
     { 
      value = GetDefault<TEnum>(); 
     } 

     // ... do some other stuff 

     // just to get code to compile 
     return value.ToString(); 
    } 

    public static TEnum GetDefault<TEnum>() where TEnum : struct, T 
    { 
     T definedDefault; 
     if (!s_defaults.TryGetValue(typeof(TEnum), out definedDefault)) 
     { 
      // This is the only time you'll have to box the defined default. 
      definedDefault = (T)Enum.GetValues(typeof(TEnum)).GetValue(0); 
      s_defaults[typeof(TEnum)] = definedDefault; 
     } 

     // Every subsequent call to GetDefault on the same TEnum type 
     // will unbox the same object. 
     return (TEnum)definedDefault; 
    } 
} 
+0

Il tuo codice non viene compilato per me (Mono C#). –

+0

@Konrad: Questo * potrebbe * essere dovuto al fatto che avevo un errore di battitura ('TEnumvalue'-senza spazio). Inoltre non ho incluso un valore di ritorno. Sarei curioso di sapere se compilazione per Mono ora che ho aggiornato l'esempio. –

+0

L'avevo già corretto, non ha aiutato. Stranamente, ora compila (+1, hack elegante!) - ma ha lo stesso problema delle altre soluzioni, ovvero che "default" restituisce realmente "0", che potrebbe essere un valore non definito nell'enumerazione effettiva e quindi non è il risultato giusto C'è il problema aggiunto che la tua soluzione non funziona più come un metodo di estensione. –