2012-09-16 7 views
5

eine Enumeration wie folgt gegeben:Wie kann ich Generics verwenden, um einen IEnumerable aus einem Enum zu erstellen?

public enum City { 
    London = 1, 
    Liverpool = 20, 
    Leeds  = 25 
} 

public enum House { 
    OneFloor = 1, 
    TwoFloors = 2 
} 

ich den folgenden Code bin mit einem IEnumerable geben Sie mir:

City[] values = (City[])Enum.GetValues(typeof(City)); 
var valuesWithNames = from value in values      
    select new { value = (int)value, name = value.ToString() }; 

Der Code funktioniert jedoch sehr gut, dass ich dies für eine ganze Menge zu tun haben enums. Gibt es eine Möglichkeit, einen generischen Weg zu schaffen?

+1

Das Problem ist, dass C# "Enum" Einschränkungen für generische Typen nicht erlaubt. Sie können Jon Skeets [unbeschränkte Melodie] (http://code.google.com/p/unconstrained-melody/) verwenden. – Adam

+0

Wenn Sie das 'IEnumerable' nur zur Laufzeit benötigen, können Sie reflection verwenden. Andernfalls können Sie die Verwendung von [templating] (http://msdn.microsoft.com/en-us/library/bb126445.aspx) UND reflection in Betracht ziehen. – Guillaume

Antwort

1

können Sie diese Funktion helfen:

public static IEnumerable<KeyValuePair<int, string>> GetValues<T>() where T : struct 
{ 
     var t = typeof(T); 
     if(!t.IsEnum) 
      throw new ArgumentException("Not an enum type"); 

     return Enum.GetValues(t).Cast<T>().Select (x => 
       new KeyValuePair<int, string>(
        (int)Enum.ToObject(t, x), 
        x.ToString())); 
} 

Verbrauch:

var values = GetValues<City>(); 
+0

'InvalidOperationException' ist definiert als *" Die Ausnahme, die ausgelöst wird, wenn ein Methodenaufruf für den aktuellen Status des Objekts ungültig ist.„* Das scheint wie ein wirklich irreführend Ausnahme zu werfen. – Adam

+0

@codesparkle Vielleicht. Ich habe es geändert' ArgumentException' – Magnus

+0

A 'TypeArgumentException' wie das in * UnconstrainedMelody * definiert wäre ideal. Die am besten passenden vordefinierten Ausnahme ist wahrscheinlich 'ArgumentException' obwohl * („Die Ausnahme, die ausgelöst wird, wenn eines der Argumente, ein Verfahren zur Verfügung gestellt nicht gültig ist.“) * – Adam

1

Warum nicht:

var result = GetValues<City>(); 

Wenn Sie Constraint generic T als enum machen möchten, weil enumdirekt nicht als generische contraint verwendet werden:

IEnumerable<object> GetValues<T>() 
    { 
     return Enum.GetValues(typeof (T)) 
        .Cast<T>() 
        .Select(value => new {  
              value = Convert.ToInt32(value), 
              name = value.ToString() 
             }); 

    } 

So können Sie verwenden aber enum erbt von der Schnittstelle IConvertible, glaube, dass dieser Weg in Ordnung ist:

IEnumerable<object> GetValues<T>() where T: struct, IConvertible 
{} 

ersetzen IEnumerable<object> durch Dictionary:

Dictionary<int, string> GetValues<T>() where T : struct, IConvertible 
{ 
    return Enum.GetValues(typeof (T)).Cast<T>() 
       .ToDictionary(value => Convert.ToInt32(value), 
          value => value.ToString()); 
} 

bearbeiten: Als Magnus Kommentar, wenn Sie die Reihenfolge der Elemente müssen sicherstellen, Wörterbuch nicht die Option. Definieren Sie Ihren eigenen starken Typ wäre besser.

+0

Ich sehe zwei Probleme mit der Rückgabe eines Wörterbuchs: Erstens ist es ungeordnet. Zweitens scheint es unnötig, ein Wörterbuch zurückzugeben, wenn es nicht zum Nachschlagen verwendet wird. – Magnus

+0

@Magnus: True mit ungeordneten, Grund, warum ich benutze ist Dictionary ist stärker Typ als IEmmmerable . –

3

Verwenden unconstrained melody Jon Skeet.

using UnconstrainedMelody; 

Sie können Ihre Enum-Werte in eine Dictionary<int, string> und dann aufzählen über sie gesagt:

var valuesAsDictionary = Enums.GetValues<City>() 
           .ToDictionary(key => (int)key, value => value.ToString()); 

Aber brauchen Sie vermutlich nicht einmal das zu tun. Warum nicht einfach über die Werte direkt aufzählen:

foreach (var value in Enums.GetValues<City>()) 
{ 
    Console.WriteLine("{0}: {1}", (int)value, value); 
} 
+0

Warum werfen Sie' int' und nicht 'T'? Aufzählungen müssen ints nicht sein , und es gibt keinen Grund, warum Sie eine 'Wörterbuch nicht zurückgeben kann ' statt. – Lee

+1

@Lee In der Frage int und String sie ausdrücklich wünscht. – Magnus

+0

@Lee aber dann wieder, warum ein Wörterbuch erstellen überhaupt, wenn alle Informationen, die Sie brauchen, existiert innerhalb des eNUM-Wertes selbst? das ist der Punkt, den ich in der zweiten Hälfte meiner Antwort auszudrücken versucht. – Adam

Verwandte Themen