Selecting enum values based on key names

不羁的心 提交于 2020-12-29 12:09:53

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!