Choosing enumeration values ​​based on key names

I have an enumeration like this:

public enum Animals { CatOne = 12, CatTwo = 13, CatThree = 14, DogOne = 21, DogTwo = 22 }; 

Great.

Now I want to get the values ​​of all cats. What I'm trying to do is the following:

 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 is working fine. He also looks ugly. Why can't I do something like

 Animals .Select(r => (int)r) .Where(r => r.StartsWith("Cat")) .ToArray(); 

I know this will not work. So, there is a better way to get all enum values ​​that start on a specific line.

I know that I could use regex to avoid false positives, but for now I keep it simple.

Thanks.

+4
source share
4 answers

Here's a compromise code set - it's not as clean as what you are looking for, but it is much better than the version of the foreach loop.

 Enum.GetValues(typeof(Animals)).OfType<Animals>() .Where(x => x.ToString().StartsWith("Cat")) .Select(x => (int)x).ToArray(); 
+10
source

Well, the easiest approach is to just 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 casting 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 from Cast<> to OfType<> here, since we really expect that each value will be Animals - if something goes wrong, the exception is completely fine!)

However, all this seems a little unpleasant to me - adding any value to the names of the enumerated values, you always feel a little hairy, and even more parsing specific bits of the name. You can try to decorate each value with an attribute to indicate a “group”.

I also suggest calling enum Animal , not Animals - only flag-based enumerations should usually be multiple, and the "collection of Animals values" sounds distinctly odd.

(In addition, you can look at my Unconstrained Melody project, which allows you to use safe and efficient shared access to type enumerations using common restrictions that are legal in IL but cannot be expressed in C # ...)

+14
source

The best way to do this is to use 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 can renumber your enumeration and not knowing exactly what you need to do with these values, it's hard to say whether it suits you or not.

+2
source

Somewhat ugly, but might suit your case:

In this case, the cats will be actual numbers, not integers.

 var cats = Enum.GetNames(typeof(Animals)) .Where (e => e.StartsWith("Cat")) .Select (e => Enum.Parse(typeof(Animals), e)); 
+1
source

Source: https://habr.com/ru/post/1468739/


All Articles