问题
I have an enum like so:
public enum Animals
{
CatOne = 12,
CatTwo = 13,
CatThree = 14,
DogOne = 21,
DogTwo = 22
};
Great.
Now I want to get the values of all the cats.. What I'm trying to do is this:
public static int[] GetCatValues()
{
List<int> catValues = new List<int>();
foreach(var cat in Enum.GetNames(typeof(Animals)))
{
Animals animal;
if(cat.StartsWith("Cat"))
{
Enum.TryParse(cat, out animal);
catValues.Add((int)animal);
}
}
return catValues.ToArray();
}
Which works okay. Except it looks ugly. Why can't I do something like
Animals
.Select(r => (int)r)
.Where(r => r.StartsWith("Cat"))
.ToArray();
I know that doesn't work. So is there a better way of getting all values of enum that starts with certain string.
I know I could probably use regex to avoid false positives, but, I am keeping it simple for now.
Thanks.
回答1:
Here's a compromise set of code - it's not as clean as what you're looking for, but it's far better than the foreach loop version.
Enum.GetValues(typeof(Animals)).OfType<Animals>()
.Where(x => x.ToString().StartsWith("Cat"))
.Select(x => (int)x).ToArray();
回答2:
Well the simplest approach is simply to get the name using ToString
:
return ((Animals[]) Enum.GetValues(typeof(Animals)))
.Where(r => r.ToString().StartsWith("Cat"))
.Select(r => (int) r) // Assuming you want this
.ToArray();
Or using Cast<>
to avoid the cast to Animals[]
:
return Enum.GetValues(typeof(Animals))
.Cast<Animals>()
.Where(r => r.ToString().StartsWith("Cat"))
.Select(r => (int) r) // Assuming you want this
.ToArray();
(I prefer Cast<>
to OfType<>
here as we really are expecting every value to be Animals
- if anything isn't, an exception is entirely appropriate!)
However, this all feels slightly icky to me - attaching any importance to the names of enum values always feels a little bit hairy, and parsing specific bits of the name even more so. You might want to try decorating each value with an attribute to specify a "group".
I'd also suggest calling the enum Animal
rather than Animals
- only flag-based enums should generally be plural, and "a collection of Animals
values" sounds distinctly odd.
(Also, you may want to look at my Unconstrained Melody project which allows for type-safe, efficient generic access to enums, via generic constraints which are legal in IL but can't be expressed in C#...)
回答3:
The better way to do this would be by using flags.
[Flags]
public enum Animals
{
CatOne = 1,
CatTwo = 2,
CatThree = 4,
DogOne = 8,
DogTwo = 16,
AllCats = Animals.CatOne | Animals.CatTwo | Animals.CatThree,
AllDogs = Animals.DogOne | Animals.DogTwo
};
Of course, this will only work if you are able to renumber your enum, and without knowing exactly what you need to do with these values it's hard to say if it would suit you or not.
回答4:
Somewhat ugly, but might suit your case:
In this case, the cats will be the actual Enums and not integers.
var cats = Enum.GetNames(typeof(Animals))
.Where (e => e.StartsWith("Cat"))
.Select (e => Enum.Parse(typeof(Animals), e));
来源:https://stackoverflow.com/questions/15365395/selecting-enum-values-based-on-key-names