2010-02-11 15 views
36

ho regolarmente chiesto perché C# non ha ancora implemeted un Enum.Parse genericoversione generica di Enum.Parse in C#

Diciamo che ho

enum MyEnum 
{ 
    Value1, 
    Value2 
} 

E da un file XML/DB ingresso I desidero creare un Enum.

MyEnum val = (MyEnum)Enum.Parse(typeof(MyEnum), "value1", true); 

Potrebbe non sono state attuate come qualcosa di simile

MyEnum cal = Enum.Parse<MyEnum>("value1"); 

Questo potrebbe sembrare un piccolo problema, ma sembra come un trascurato uno.

Qualche idea?

risposta

30

È già implementato in .NET 4;) Dai un'occhiata a here.

MyEnum cal; 
if (!Enum.TryParse<MyEnum>("value1", out cal)) 
    throw new Exception("value1 is not valid member of enumeration MyEnum"); 

Anche la discussione here contiene alcuni punti interessanti.

+6

Tale nesso è al non generica ' Metodo Enum.Parse'. Intendevi collegare al nuovo metodo 'Enum.TryParse '? http://msdn.microsoft.com/en-us/library/system.enum.tryparse%28VS.100%29.aspx –

+3

È interessante che lo abbiano vincolato a struct, new() invece di aggiungere un nuovo vincolo enum al linguaggio. –

+0

Scusa, l'ho già risolto, questo è esattamente ciò che intendevo;) –

6

Sebbene la limitazione a System.Enum non sia consentita da C#, è consentito in .NET e C# può utilizzare tipi o metodi con tali vincoli. Vedi la libreria Unconstrained Melody di Jon Skeet, che include il codice che fa esattamente quello che vuoi.

+18

Humbug, non riesco nemmeno a collegare la mia libreria senza che qualcuno ci arrivi prima;) –

16

E nella sintassi desiderata della domanda:

MyEnum cal = Toolkit.Parse<MyEnum>("value1"); 

Nota: Dal momento che C# vi proibisce di aggiungere estensioni statiche, si deve ospitare la funzione altrove. io uso un Toolkit classe statica che contiene tutti questi bit utili:

/// <summary> 
/// Converts the string representation of the name or numeric value of one or 
// more enumerated constants to an equivalent enumerated object. 
/// </summary> 
/// <typeparam name="TEnum">An enumeration type.</typeparam> 
/// <param name="value">A string containing the name or value to convert.</param> 
/// <returns>An object of type TEnum whose value is represented by value</returns> 
/// <exception cref="System.ArgumentNullException">enumType or value is null.</exception> 
/// <exception cref=" System.ArgumentException"> enumType is not an System.Enum. -or- 
/// value is either an empty string or only contains white space.-or- 
/// value is a name, but not one of the named constants defined for the enumeration.</exception> 
/// <exception cref="System.OverflowException">value is outside the range of the underlying type of enumType.</exception> 
public static TEnum Parse<TEnum>(String value) where TEnum : struct 
{ 
    return (TEnum)Enum.Parse(typeof(TEnum), value); 
} 
0

Mentre tweaking un po 'con alcuni metodi, cercando di costruire qualcosa di simile alla proposta iniziale:

MyEnum cal = Enum.Parse<MyEnum>("value1"); 

mi sembrava che questa sintassi non sarà possibile in C#, poiché il tipo Enum è considerato non annullabile.

Se si chiama il metodo "Enum.TryParse" passando un valore non corrispondente a un elemento dell'enumerazione, il valore predefinito dell'Enum verrà restituito nella variabile "out". Ecco perché abbiamo bisogno di testare il risultato "Enum.TryParse" prima, dal momento che semplicemente chiamando

MyEnum cal; 
Enum.TryParse<MyEnum>("value1", out cal); 

e controllando il valore "cal" non sempre dare un risultato affidabile.

+3

il 'Parse' generico potrebbe semplicemente essere un wrapper attorno a' TryParse' e ​​lanciare una 'ArgumentException' se' TryParse' restituisce 'false'. –

+0

Può semplicemente generare un'eccezione invece del valore predefinito. Lo stesso della versione non generica di Parse. – Maxim

+0

L'idea è di evitare (quando possibile) la gestione delle eccezioni, che è considerata un anti-pattern per il controllo del flusso (rif. Https://web.archive.org/web/20140430044213/http://c2.com/cgi- bin/wiki? DontUseExceptionsForFlowControl). In base alle specifiche API, il metodo Enum.TryParse "elimina la necessità di gestire le eccezioni durante l'analisi della rappresentazione della stringa di un valore di enumerazione." (ref. https://msdn.microsoft.com/en-us//library/dd991317(v=vs.110).aspx) –

2
public class EnumHelper 
{ 
    public static T? TryParse<T>(string text) 
     where T: struct 
    { 
     if (string.IsNullOrEmpty(text)) 
     { 
      return null; 
     } 

     T r; 

     if (Enum.TryParse<T>(text, out r)) 
     { 
      return r; 
     } 

     return null; 
    } 
} 
1

leggermente modificata versione di @ risposta di ian-Boyd, utilizzando un metodo di estensione per evitare la necessità di specificare un nome classe statica nella chiamata:

MyEnum cal = "value1".Parse<MyEnum>(); 

/// <summary> 
/// Converts the string representation of the name or numeric value of one or 
// more enumerated constants to an equivalent enumerated object. 
/// </summary> 
/// <typeparam name="TEnum">An enumeration type.</typeparam> 
/// <returns>An object of type TEnum whose value is represented by value</returns> 
/// <exception cref="System.ArgumentNullException">enumType or value is null.</exception> 
/// <exception cref=" System.ArgumentException"> enumType is not an System.Enum. -or- 
/// value is either an empty string or only contains white space.-or- 
/// value is a name, but not one of the named constants defined for the enumeration.</exception> 
/// <exception cref="System.OverflowException">value is outside the range of the underlying type of enumType.</exception> 
public static TEnum Parse<TEnum>(this String value) where TEnum : struct 
{ 
    return (TEnum)Enum.Parse(typeof(TEnum), value); 
} 
Problemi correlati