【问题标题】:Selecting enum values based on key names根据键名选择枚举值
【发布时间】:2013-03-12 15:31:53
【问题描述】:

我有一个像这样的枚举:

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

太棒了。

现在我想获取所有猫的值。我想做的是:

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();
}

这行得通。除了看起来很丑。为什么我不能做类似的事情

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

我知道那行不通。那么有没有更好的方法来获取以某个字符串开头的所有枚举值。

我知道我可能会使用正则表达式来避免误报,但是,我现在保持简单。

谢谢。

【问题讨论】:

  • r.ToString().StartsWith("Cat"))
  • 你为什么要通过寻找以cat开头的条目来获取所有狗的价值?
  • 为什么要使用正则表达式,您可以使用 Linq
  • @MattBurland,哎呀,我在输入问题时正在构建问题,所以它是一个 brin-fo(类似于错字,但我的大脑有误)
  • @DJKRAZE 我可以吗?我不知道,这就是我想在这里找到的!

标签: c# linq enums


【解决方案1】:

这是一组折衷的代码 - 它不像您要寻找的那样干净,但比 foreach 循环版本要好得多。

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

【讨论】:

  • 现在我很困惑我应该接受什么答案,这个还是 Jon Skeet 的
  • @LocustHorde - 如果你接受我的,我会很高兴,因为我首先得到了这个答案,但乔恩的 far 更全面,并且有一个有用的链接,我会跟进,所以我可能会建议他。我相信,一般规则是“谁帮助更多”,所以这就是你的决定。
  • 在 Jon Skeet 的版本出现之前,我最终使用了这个答案(后来用 Jon Skeet 的 Cast 而不是 OfType 的建议修改)所以我选择了这个答案。谢谢。
【解决方案2】:

最简单的方法就是使用ToString 获取名称:

return ((Animals[]) Enum.GetValues(typeof(Animals)))
    .Where(r => r.ToString().StartsWith("Cat"))
    .Select(r => (int) r) // Assuming you want this
    .ToArray();

或者使用Cast&lt;&gt; 来避免转换为Animals[]

return Enum.GetValues(typeof(Animals))
    .Cast<Animals>()
    .Where(r => r.ToString().StartsWith("Cat"))
    .Select(r => (int) r) // Assuming you want this
    .ToArray();

(我更喜欢Cast&lt;&gt; 而不是OfType&lt;&gt;,因为我们真的希望每个值都是Animals - 如果不是,例外是完全合适的!)

然而,这一切对我来说有点恶心 - 重视枚举值的名称总是感觉有点毛茸茸,解析名称的特定位更是如此。您可能想尝试使用属性来装饰每个值以指定“组”。

我还建议调用枚举 Animal 而不是 Animals - 只有基于标志的枚举通常应该是复数,并且“Animals 值的集合”听起来很奇怪。

(另外,你可能想看看我的Unconstrained Melody 项目,它允许通过在 IL 中合法但不能在 C# 中表达的泛型约束对枚举进行类型安全、高效的泛型访问...)

【讨论】:

  • 我认为你不能直接在枚举类型上调用.Where()Animals.Where() 不存在。
  • @Bobson:Doh,我以为Animals 已经是一个归还所有动物的属性。正在编辑...
  • @JonSkeet,第一行周围需要有一个额外的括号,否则返回试图返回 Animals[] 本身.. 所以第一行 = return ((Animals[])Enum.GetValues(typeof(Animals))).Where....
  • @Bobson:我现在包含了一个使用 Cast 的版本 - 以及我对 Cast 的推理而不是 OfType
  • @JonSkeet - 很好的推理。而且我绝对同意从枚举的名称中得出含义。
【解决方案3】:

更好的方法是使用标志。

[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 
};

当然,这仅在您能够重新编号枚举时才有效,并且在不确切知道您需要对这些值做什么的情况下,很难说它是否适合您。

【讨论】:

  • ...对不起,我怎么能用这个获得所有猫的价值?!
  • 哦,我需要将我的枚举值与AllCats 值进行比较。嗯,我正在尝试做一些稍微不同的事情,所以我需要得到两个枚举的交集,所以这个暂时不适合我的目的!
  • 所有猫的值都在AllCats中。他们是ORed 在一起。要测试一个特定的值是否是一只猫,您可以执行Animals.AllCats &amp; myValue == myValue 之类的操作。如果 myValue 是一只猫,这将评估为 true。
  • 是的,我可以看到,但是我应该获取所有值并与另一个枚举执行交集,所以对于这种情况,至少它是不可接受的。但是谢谢你,我没有知道我可以或它! +1
【解决方案4】:

有点丑,但可能适合你的情况:

在这种情况下,猫将是实际的枚举而不是整数。

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

【讨论】:

    猜你喜欢
    • 2019-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多