tags:

views:

384

answers:

8

I am working with the static method

Enum.GetValues(typeof(SomeEnum));

This method works great when all you need to do is enumerate the values, but for some reason it returns a very simple form of the Array class. I am trying to find an easy way to turn it's return value into a more "normal" collection class like a regular array or List<>.

So far if I want to do that I have to enumerate through the output of Enum.GetValues(typeof(SomeEnum)); and add them one by one to a List<>.

Any ideas how to do this more cleanly?

Answer:

The key is to cast the return result --

SomeEnum[] enums = (SomeEnum[]) Enum.GetValues(typeof(SomeEnum));

If you need a List then jus wrap it in parenthesis and ToList it like so:

List<SomeEnum> list = ((SomeEnum[]) Enum.GetValues(typeof(SomeEnum))).ToList();
A: 

How about this:

    List<SomeEnum> list = new List<SomeEnum>();
    foreach (SomeEnum value in Enum.GetValues (typeof (SomeEnum)))
    {
        if (condition)
            list.Add(value);
    }
Igor Brejc
That is what I already have :) I think I have found a cleaner solution. Let me post it.
Alex Baranosky
Well, next time you should include in your question what you already have. And you've originally stated you want a solution for adding items one by one...
Igor Brejc
Igor, please re-read my question. I ask for a way to turn the return valu eof Enum.GetValues() into an array of List<>
Alex Baranosky
Ok, my apologies... too early in the day :(
Igor Brejc
+1  A: 

REVISION (12-Sep-2009 ~2:20 PM EST):

So, I made this suggestion last night on the basis that Enum.GetValues returns an Array, and I thought that Array implements IEnumerable<T>:

I believe you can construct a List<T> passing any IEnumerable<T> as a parameter into the constructor. So you should be able to just do this:

List<SomeEnum> values = new List<SomeEnum>(Enum.GetValues(typeof(SomeEnum)));

However, GordonG quite promptly replied to my answer indicating that it doesn't compile. (Ordinarily I would test my answer, but I was at a computer without any development tools at the time and was also feeling quite [unreasonably] sure of myself.)

After some downvotes and heavy soul-searching I resolved to get to the bottom of this matter (after a good night's sleep). Turns out, according to Microsoft's documentation on the Array class here, that Array does implement IEnumerable<T>, but only at run time (so, not at compile time--hence the failure to compile). This, in hindsight, makes sense: Enum.GetValues is not a generic method, and so it cannot know what sort of generic collection to return beforehand. (At least that's how I understand it.)

Anyway, what this all means is that you can legally cast an Array to an IEnumerable<T> provided that you get your type right. And so, at last I can present my final answer, which is really the same as my original answer but with a simple cast thrown in to make everything legal:

// splitting into two lines just for readability's sake
List<SomeEnum> values;
values = new List<SomeEnum>((IEnumerable<T>) Enum.GetValues(typeof(SomeEnum)));

Of course, in retrospect, GordonG wasn't dead set on getting a List<T>, which means his own answer of casting to SomeEnum[] is really just as good.

Dan Tao
doesn't compile for me.
Alex Baranosky
And you can also create a List and supply its AddRange method with an array.
rossisdead
Dude you are getting upvoted for something that doesn't even compile! ;)
Alex Baranosky
Just tried, doesn't work.
Pwninstein
The AddRange thing doesn't compile either.
Alex Baranosky
Dan, hehe, that won't work either. Now you see why I asked this seemingly simple question. Enum.GetValues() returns some strange archaic form of Array.
Alex Baranosky
@GordonG: but in your answer, you are casting to an array of SomeEnum, which should implement IEnumerable<SomeEnum> unless I am mistaken? Did you try that one and it didn't compile either? Maybe it's just too late...
Dan Tao
I could probably put my answer into a List constructor and get a list, but I want an array for this code I'm using. I could just as easily take my code and put parentheses around it and call .ToList() too I assume. In my question I didn't specify needing a List over an array. I just wanted a List *OR* and array :)
Alex Baranosky
A little soul searching never hurt anybody ;)
Alex Baranosky
+3  A: 

I found here you can just do this:

SomeEnum[] enums = (SomeEnum[]) Enum.GetValues(typeof(SomeEnum));

And if you need a List just use .ToList() at the end, like this:

List<SomeEnum> list = ((SomeEnum[]) Enum.GetValues(typeof(SomeEnum))).ToList();

Or if you like this better:

List<SomeEnum> list2 = new List<SomeEnum>((SomeEnum[]) Enum.GetValues(typeof(SomeEnum)));
Alex Baranosky
You have name of your enum duplicated. That's annoying when writing code.
Konstantin Spirin
+1  A: 

This should work:

List<MyEnum> enums = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).ToList();

The reason ToList() didn't work in the solution you posted in your question was that you're missing a set of parens around the casted portion. Hope this helps!

Pwninstein
compiled successfully .... working....
Mahin
The reason this answer:List<SomeEnum> values = new List<SomeEnum>(Enum.GetValues(typeof(SomeEnum)));didn't compile is because of the lack of (SomeEnum[]) cast...
Alex Baranosky
Ah, I was looking at the code you included at the end of your original question (which includes the cast). Sorry! :)
Pwninstein
Don't worry about it, I was just clarifying :)
Alex Baranosky
+4  A: 

If you're using .NET 3.5, you can also use Cast<T> and ToList extension methods.

IEnumerable<SomeEnum> enums = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>();

You can also get a list if you want to

List<SomeEnum> list =  Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToList();
Mehmet Aras
+2  A: 

Inspired by Jon Skeet's unconstrained-melody, I came up with version I like more:

public static class Enum<T>
    where T: struct
{
    static Enum()
    {
        Trace.Assert(typeof(T).IsEnum);
    }

    public static ReadOnlyCollection<T> Values = ((T[])Enum.GetValues(typeof(T))).ToList().AsReadOnly();
}

and usage:

var values = Enum<BindingFlags>.Values;

Good thing is this version works faster for multiple calls because it does not create new array on every time.

Konstantin Spirin
@Konstantin: I prefer UnconstrainedMelody as it means you don't need the type argument check. I would make the type argument check a normal `if (...) throw` though - why do you want to keep going if you're not in debug mode? I'd also add the "where T : struct" constraint - it's not as much as UnconstrainedMelody provides, but it's definitely better than nothing.
Jon Skeet
I'm tempted to take the idea of a field/property rather than a method call though. So far my `Enums` type is non-generic, relying on generic *methods* instead to get the benefit of type inference... but I could have a generic one as well. It might be a bit confusing though.
Jon Skeet
Thanks Jon, I've changed Debug to Trace and added struct constraint. I must say I almost like it now.
Konstantin Spirin
+3  A: 

I have a brand new library (UnconstrainedMelody) which helps with this. It can return the values in a strongly typed array or in an immutable list:

SomeEnum[] array = Enums<SomeEnum>.GetValuesArray()
IList<SomeEnum> list = Enums<SomeEnum>.GetValues();

It's generic and has a constraint on the type parameter to make sure it's genuinely an enum. This isn't possible in normal C#, but the library does a bit of furtling to make it work. I like the second form more, because we cache the list - the fact that it's immutable means we can return the same reference again and again.

There are various other utility methods to make it easier to work with flags enums etc.

Enjoy.

Jon Skeet
Hey Jon, I took a look at your link. It's pretty cool that you found a way to jury rig the compiler :)
Alex Baranosky
Hey Jon, I wanted to download the source so I went to my Tortoise SVN right-clicked and selected Import. then entered: http://unconstrained-melody.googlecode.com/svn/trunk/ unconstrained-melody-read-only, this asked me a for a login... so I tried the below:http://unconstrained-melody.googlecode.com/svn/trunk/, same thing...how can I get the soruce code?
Alex Baranosky
Hmmm... I'm not sure why the anonymous access isn't working. You can view individual files by selecting "browse" - but I'll try to get a source download up there in a minute...
Jon Skeet
Okay, source zip file is now up: http://code.google.com/p/unconstrained-melody/downloads/list
Jon Skeet
Thanks, muchas gracias.
Alex Baranosky
Svn anonymous access seems to be live again now... I was just about to notify the appropriate team, but it's working for me :)
Jon Skeet
Maybe it is something with Tortoise, I don't use it often. Because they are asking me for authentication.
Alex Baranosky
Hey Jon, I found this, you might find it interesting. At the bottom he talks abotu how to use Tortoise SVN with Google code. It is a rather intensive process, hehe. Do you just use a commandline SVN? Will usign a commandline version make my life easier?
Alex Baranosky
oops forgot the link:http://code.google.com/p/flex-cb/wiki/Checkout_Code
Alex Baranosky
Doh - I've worked out what you're doing wrong. Using *import* is meant to add files to the repository. You want *export* (or checkout).
Jon Skeet
Jon you are the man. I'm not used to Subversion's terminology. It seemed to make sense that I was IMPORTING files from the repository... All that matters is it worked :D
Alex Baranosky
@Jon: what do you think about my answer here: http://stackoverflow.com/questions/1414277/simple-form-of-array-class-and-enum-getvalues/1414372#1414372 ?
Konstantin Spirin
@Konstantin: I've responded to the answer directly.
Jon Skeet
A: 

Updated solution (from 'Konstantin Spirin') for .NET framwork 2.0:

public static class Enum<T> where T : struct
{
    static Enum()
    {
        Trace.Assert(typeof(T).IsEnum);
    }

    public static ReadOnlyCollection<T> Values = new ReadOnlyCollection<T>(((T[])Enum.GetValues(typeof(T))));
}
psulek