31

In .Net it is possible to iterate through an enumeration by using

System.Enum.GetNames(typeof(MyEnum)) 

or

System.Enum.GetValues(typeof(MyEnum))

In Silverlight 3 however, Enum.GetNames and Enum.GetValues are not defined. Does anyone know an alternative?

eriksmith200
  • 2,159
  • 5
  • 22
  • 33
  • 9
    It's ridiculous that this isn't in the framework. Download size is no excuse to torture the devs. – Bryan Legend Dec 26 '10 at 07:10
  • if anyone needs, specifically, GetEnumValues() and GetEnumNames(); I have implemented them (based on the answer by ptoinson and Shimmy below) as a response to the following question: http://stackoverflow.com/questions/7062208/how-do-i-create-a-getenumvalues-extension-method-in-silverlight-that-works-the-sa , and I think they are equivalent to the regular (but non-Silverlight) .NET functions of the same name. – shelleybutterfly Aug 15 '11 at 19:44

4 Answers4

30

Or maybe strongly typed using linq, like this:

    public static T[] GetEnumValues<T>()
    {
        var type = typeof(T);
        if (!type.IsEnum)
            throw new ArgumentException("Type '" + type.Name + "' is not an enum");

        return (
          from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
          where field.IsLiteral
          select (T)field.GetValue(null)
        ).ToArray();
    }

    public static string[] GetEnumStrings<T>()
    {
        var type = typeof(T);
        if (!type.IsEnum)
            throw new ArgumentException("Type '" + type.Name + "' is not an enum");

        return (
          from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
          where field.IsLiteral
          select field.Name
        ).ToArray();
    }
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
ptoinson
  • 2,013
  • 3
  • 21
  • 30
  • 1
    Better to put `where T : struct,IConvertible` in method definition to get closer to restrict `T` to enums only. – Kamyar Sep 04 '11 at 08:19
27

I figured out how to do this without making assumptions about the enum, mimicking the functions in .Net:

public static string[] GetNames(this Enum e) {
    List<string> enumNames = new List<string>();

    foreach (FieldInfo fi in e.GetType().GetFields(BindingFlags.Static | BindingFlags.Public)){
        enumNames.Add(fi.Name);
    }

    return enumNames.ToArray<string>();
}

public static Array GetValues(this Enum e) {
    List<int> enumValues = new List<int>();

    foreach (FieldInfo fi in e.GetType().GetFields(BindingFlags.Static | BindingFlags.Public)) {
        enumValues.Add((int)Enum.Parse(e.GetType(), fi.Name, false));
    }

    return enumValues.ToArray();
}
eriksmith200
  • 2,159
  • 5
  • 22
  • 33
  • 1
    I would however suggest that you return an IList for the top method and an IList for the second one. And remember that this will not support enums that represent a long value. – stevehipwell Jun 25 '09 at 11:53
  • 2
    You could support non-int types by getting the underlying type (Enum.GetUnderlyingType()) – dcstraw Nov 11 '10 at 22:58
  • 3
    This solution leaves a bit to be desired. The usage syntax requires you to provide an instance of the enumeration type, while the original .net methods let you work on type directly. In that respect I find the answer of @ptoinson better. Its syntax is simple and clean. GetEnumValues() – angularsen Apr 26 '11 at 20:05
3

I haven't tried this, but the reflection APIs should work.

John Fisher
  • 22,355
  • 2
  • 39
  • 64
1

I belive this is the same as in the .NET Compact Framework. If we make the assumption that your enum values start at 0 and use every value until their range is over the following code should work.

public static IList<int> GetEnumValues(Type oEnumType)
{
  int iLoop = 0;
  bool bDefined = true;
  List<int> oList = new List<int>();

  //Loop values
  do
  {
    //Check if the value is defined
    if (Enum.IsDefined(oEnumType, iLoop))
    {
      //Add item to the value list and increment
      oList.Add(iLoop);
      ++iLoop;
    }
    else
    {
      //Set undefined
      bDefined = false;
    }
  } while (bDefined);

  //Return the list
  return oList;
}

Obviously you could tweak the code to return the enum names or to match diferent patterns e.g. bitwise values.

Here is an alternate version of the method that returns a IList<EnumType>.

public static IList<T> GetEnumValues<T>()
{
  Type oEnumType;
  int iLoop = 0;  
  bool bDefined = true;  
  List<T> oList = new List<T>();  

  //Get the enum type
  oEnumType = typeof(T);

  //Check that we have an enum
  if (oEnumType.IsEnum)
  {
    //Loop values  
    do
    {
      //Check if the value is defined    
      if (Enum.IsDefined(oEnumType, iLoop))
      {
        //Add item to the value list and increment      
        oList.Add((T) (object) iLoop);
        ++iLoop;
      }
      else
      {
        //Set undefined      
        bDefined = false;
      }
    } while (bDefined);
  }

  //Return the list  
  return oList;
}
stevehipwell
  • 56,138
  • 6
  • 44
  • 61
  • I know you had the caveat of assuming contiguous values, but in particular any [Flags] attributed enums wouldn't work. – dcstraw Nov 11 '10 at 22:56
  • @dcstraw - Read the last sentance, I aknowledged that you could use a different pattern to match bitwise values e.g. [Flags]; to do this `++iLoop;` becomes `iLoop = iLoop << 1;`. – stevehipwell Nov 12 '10 at 08:41
  • A request if you don't mind: since this doesn't return an Array of specific enumerated types, but instead a List, it doesn't actually match the behavior on the .NET platform, and caused a good bit of confusion for me when trying to determine whether this function would work for another user. Would you be open to renaming it to something else? The main issue for me was that GetArrayValues(i).ToString() returns a string of the number rather than the enum name, as is returned by the actual .NET version, although I am sure there are other possible sources of confusion. – shelleybutterfly Aug 15 '11 at 19:51
  • @shelleybutterfly - Why not use `((EnumType)GetArrayValues[i]).ToString()` or in VB.NET `CType(GetArrayValues(i), EnumType).ToString()`? My answer states that the above code is just a simple example and can easily be re-written to return a different type or match a different enum pattern. – stevehipwell Aug 16 '11 at 07:32
  • Because in the questioner's case, the EnumType was not known ahead of time; only, say, `Type CurrentEnumType;` was the given. And I agree that you adequately clarified it in the follow-up text, it's just that it was a source of confusion for me (who was not familiar with the normal return value; an Array containing whatever the enum types are) because I had assumed that having the same name meant it returned the same thing as the standard .NET framework method. – shelleybutterfly Aug 16 '11 at 08:15
  • @shelleybutterfly - The method is very simple and it's clear to see what type is returned. For the sake of a couple of mins I'll post an alternate signature that will return `IList`. – stevehipwell Aug 16 '11 at 08:25
  • I am not questioning that the return type was clear; the thing that is not clear to someone that has no familiarity with the .NET call, is that this function does not have the same behavior as the framework. Not everyone is familiar with this method. I saw an identically named method and assumed that it would meet someone's need for it. So, I thought it was a reasonable request that you not leave a function up which has a mismatched signature and which thus may go against a user's expectation. – shelleybutterfly Aug 16 '11 at 08:51
  • Also, if you are returning IList with the same name, you will still have a misleading function name, not matching the .NET framework function, which returns an Array. At a minimum, code which is calling for .Length would have to be changed to .Count, so I think it also reasonable if that function not be named GetEnumValues. If you feel very strongly about it being named GetEnumValues, I won't continue to argue the point. – shelleybutterfly Aug 16 '11 at 08:51
  • @shelleybutterfly - I've tried being helpful but that hasn't worked so here are the facts. My method does not have the same signature as the framework method `MyClass.GetEnumValues` vs `Enum.GetValues`. There is nothing about this method that breaks coding guidelines. I really don't see how a programmer can be confused by this as you can read the source code. Most importantly, if you don't like it then don't use it! – stevehipwell Aug 16 '11 at 09:32
  • The name collision caused issues when I was trying to help someone out, for reasons described in three increasingly detailed comments above. I made a reasonable request, which you never directly responded to, and then simply tried to get you to understand what did actually happen. I said nothing of "coding guidelines" and what I did say was polite, and is there for anyone to see, including you. A simple "No" from you at any time would have sufficed. Moreover I had *just said* that I wouldn't continue if you felt strongly about the name! So I really don't get the need for the last comment. w/e – shelleybutterfly Aug 16 '11 at 10:36
  • @shelleybutterfly - There is NO naming collision! – stevehipwell Aug 16 '11 at 11:25
  • Sorry, *metaphorical* name collision, @Steveo3000. w/e, I've said all I care to say about it. Although, you apparently didn't take time to listen to the answer to your first question either: that we only had a `Type CurrentEnumType;' variable to work with, not a known EnumType. But you gave a function taking a template param, which can't even be filled in with a Type variable. Doesn't matter, was unnecessary anyway, already had modified another answer to be identical to the .NET framework's Enum.GetEnumValues call, with no restrictions on value. But you seem to have missed much of what I said. – shelleybutterfly Aug 16 '11 at 11:44