【问题标题】:Determining if enum value is in list (C#)确定枚举值是否在列表中(C#)
【发布时间】:2008-10-02 20:29:50
【问题描述】:

我正在构建一个有趣的小应用程序来确定我是否应该骑自行车上班。

我想测试一下是下雨还是雷暴。

public enum WeatherType : byte
{ Sunny = 0, Cloudy = 1, Thunderstorm = 2, Raining = 4, Snowing = 8, MostlyCloudy = 16 }

我在想我可以这样做:

WeatherType _badWeatherTypes = WeatherType.Thunderstorm | WeatherType.Raining;
if(currentWeather.Type == _badWeatherTypes)
{
 return false;//don't bike
}

但这不起作用,因为 _badWeatherTypes 是两种类型的组合。我想将它们分开,因为这应该是一种学习体验,并且将其分开可能在其他情况下很有用(IE,发票未支付原因等......)。

我也不想这样做:(这将取消为多人配置的能力)

if(WeatherType.Thunderstorm)
{
 return false; //don't bike
}
etc...

【问题讨论】:

    标签: c# .net enums


    【解决方案1】:

    您当前的代码会说明它是否完全“下雨打雷”。要确定是否“下雨、打雷以及可能是其他情况”,您需要:

    if ((currentWeather.Type & _badWeatherTypes) == _badWeatherTypes)
    

    要确定是“下雨还是雷雨,可能还有别的什么”,您需要:

    if ((currentWeather.Type & _badWeatherTypes) != 0)
    

    编辑(为了完整性):

    最好使用FlagsAttribute,即用[Flags] 装饰类型。对于这种按位逻辑,这不是必需的,但会影响ToString() 的行为方式。 C# 编译器忽略了这个属性(至少目前;C# 3.0 规范没有提到它)但是对于作为有效标志的枚举通常是一个好主意,并且它记录了该类型的预期用途。同时,约定是当您使用标志时,您将枚举名称复数 - 因此您将其更改为 WeatherTypes(因为任何实际值实际上是 0 或更多天气类型)。

    还值得思考一下“阳光明媚”的真正含义。它目前的值为 0,这意味着它没有其他所有内容;你不能同时晴天和下雨(当然,这在物理上是可能的)。请不要编写禁止彩虹的代码! ;) 另一方面,如果在您的实际用例中您真的想要一个意味着“没有所有其他值”的值,那么您就可以了。

    【讨论】:

    • [Flags] 似乎是这里的路。
    • 嗯,这绝对是一件好事 - 但它与实际问题完全正交。它既不会帮助也不会阻碍按位逻辑。
    • 您对“Sunny”的看法是正确的,我需要更改它。感谢大家的帮助。
    【解决方案2】:

    我不确定它应该是一个标志 - 我认为你应该有一个范围输入:

    • 温度
    • 下雨了多少
    • 风力强度
    • 您喜欢的任何其他输入(例如雷暴)

    然后您可以使用算法来确定条件是否足够好。

    我认为您还应该对骑自行车回家的天气保持不变的可能性有多大的投入。标准可能有所不同 - 您可以在回家后更轻松地淋浴和更换。

    如果您真的想让它变得有趣,请从天气服务 api 收集输入数据,并每天评估决定 - 是的,我应该骑车,或者不,这是一个错误。然后也许你可以让应用学会做出更好的决定。

    下一步是将您的决定“社交化”,看看其他人是否听到您正在做出相同的决定。

    【讨论】:

    • 哇,我总是错过那一步!
    【解决方案3】:

    使用 FlagsAttribute。这将允许您将枚举用作位掩码。

    【讨论】:

    • 您可以将枚举用作不带标志的位掩码;我相信 FlagsAttribute 只是改变了 ToString 的操作方式。诚然,包含它仍然是一个好主意。
    • 它只是改变了 ToString 的行为方式,但不能保证 .NET 的未来版本不会改变其他行为(例如,如果值不是 2 的幂,则编译器会发出错误)所以使用标志枚举时应始终使用它。
    • 啊,我不知道它只是改变了ToString()。很有趣。
    • 如果您不指定值,Flag 会将它们设置为 2 的幂(至少在 VB 中)。
    • 不幸的是,Flags 不会更改 C# 中的自动生成值。至于“不保证未来版本的 .NET 不会改变其他行为”——就像说“不保证垃圾收集器在未来版本中仍然可以工作,最好将变量设置为 null 以帮助它。”
    【解决方案4】:

    您需要在枚举上使用 [Flags] 属性 (check here);然后您可以使用按位并检查单个匹配项。

    【讨论】:

    • 请看我对 MagicKat 的回复。标志是可取的,但在这里不是必需的。
    【解决方案5】:

    您应该在枚举中使用 Flags 属性。除此之外,您还需要测试是否设置了特定标志:

    (currentWeather.Type & WeatherType.Thunderstorm == WeatherType.Thunderstorm)
    

    这将测试 currentWeather.Type 是否设置了 WeatherType.Thunderstorm 标志。

    【讨论】:

      【解决方案6】:

      我不会将自己限制在比特世界中。正如您所发现的,枚举和位运算符不是一回事。如果您想使用按位运算符解决这个问题,我会坚持使用它们,即不要打扰枚举。但是,我想要以下内容:

              WeatherType[] badWeatherTypes = new WeatherType[]
              {   
                  WeatherType.Thunderstorm, 
                  WeatherType.Raining
              };
      
              if (Array.IndexOf(badWeatherTypes, currentWeather.Type) >= 0)
              {
                              return false;
              }
      

      【讨论】:

      • 这正是标志枚举(位字段)的设计目的。从FlagsAttribute上的MSDN页面:位字段通常用于可能组合出现的元素列表......因此,位字段被设计为与按位或操作组合以生成未命名的值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多