【问题标题】:C# byte find string representation of all bits set/not setC#字节查找所有位设置/未设置的字符串表示
【发布时间】:2013-07-17 15:34:48
【问题描述】:

抱歉,如果这是一个重复的问题,我尝试搜索,但找不到与我的问题相关的任何内容。

我有一个字节值,其中每个位(或一组位)都意味着什么。我有一个带有自定义属性的枚举来定义这些位,如下所示:

[Flags]
public enum Config4
{
    [StringValue("Enable good-read beep")]
    GoodReadBeep = 1 << 0,
    [StringValue("Low beeper volume")]
    LowBeep = 1 << 1,
    [StringValue("Medium beeper volume")]
    MediumBeep = 1 << 2,
    [StringValue("Low beeper frequency")]
    LowFrequency = 1 << 3,
    [StringValue("Medium beeper frequency")]
    MediumFrequency = 1 << 4,
    [StringValue("Medium beeper duration")]
    MediumDuration = 1 << 5,
    [StringValue("Long beeper duration")]
    LongDuration = 1 << 6,
    [StringValue("Reserved")]
    Reserved = 1 << 7
}

问题在于,除了这些单独的定义之外,还定义了成对(甚至是组)位。例如,(LowBeep | MediumBeep) = HighBeep

假设我有一个字节值 47,我想找到它的字符串表示形式。我目前实现的方法涉及查找字节中设置的位数,然后遍历这些位并从枚举中附加字符串值。类似于以下内容:

for (int i = 0; i < bitsSet.Count; i++)
{
    answer += ((ConfigDataHolder.Config4)bitsSet[i]).GetStringValue() + ", ";
}

这会在定义位组时产生问题。在上面提到的情况下,47 将同时包含MediumBeepLowBeep,因此字符串表示应该是HighBeep,而不是单独的MediumBeepLowBeep

考虑到可能存在与设置单个位完全不同的位组,是否有更有效的方法来获取字节中设置的每个位的字符串表示形式?

谢谢 里士

【问题讨论】:

  • 确定是(LowBeep | MediumBeep) = HighBeep 吗?否则HighBeep 将为零。

标签: c# enums bit-manipulation custom-attributes


【解决方案1】:

您可以使用位掩码。看看这里的小例子:

[Flags]
public enum MySettings
{
    SettingA=1,
    SettingB=2,
    SettingC=4,
    SettingD=8
}

class Program
{
    static void Main(string[] args)
    {
        byte mySettings1 = 7;
        byte mySettings2 = 2;

        Console.WriteLine("Analyse mySetting1");
        AnalyseSettings(mySettings1);
        Console.WriteLine("Analyse mySetting2");
        AnalyseSettings(mySettings2);

        Console.ReadKey();
    }

    private static void AnalyseSettings(byte mySettings)
    {
        byte maskA = 1;
        byte maskB = 2;
        byte maskC = 4;
        byte maskD = 8;

        // Compare with bitwise and 

        if ((mySettings & maskA) == maskA)
        {
            Console.WriteLine("A Selected");
        }

        if ((mySettings & maskB) == maskB)
        {
            Console.WriteLine("B Selected");
        }
        if ((mySettings & maskC) == maskC)
        {
            Console.WriteLine("C Selected");
        }
        if ((mySettings & maskD) == maskD)
        {
            Console.WriteLine("D Selected");
        }
    }
}

按位比较非常快,您可以将结果添加到字符串生成器。 我在枚举声明中没有使用移位运算符,但它是一样的。

【讨论】:

  • 我想过这样做,但是如果有多个位组成一个设置,掩码会是什么?在我的示例中,“HighBeep”的字节掩码是什么?
  • 另外,在这段代码 sn-p 中,我似乎无法弄清楚你在哪里使用枚举。它本质上是发送一个字节并将其与本地掩码变量进行比较,对吗?如果我尝试使用枚举值执行“if”语句,我会收到一个编译器错误,基本上告诉我我不能 AND 一个字节和一个枚举值。
  • 抱歉耽搁了。您可以将 bitflag 枚举转换为 int。请参阅下面的更新源。
【解决方案2】:

您也可以将它们组合起来。看这里:

        byte maskAndB = 3;
        if ((mySettings & maskAndB) == maskAndB)
        {
            Console.WriteLine(" A and B selected");
        }

这就像数字的二进制表示。 11 = 3 和 101 = 5。

我想知道您为什么要使用移位运算符?您还使用左移并从数据类型的最高位开始。

您还可以将枚举转换为 int 并再次检查:

[Flags]
public enum MySettings
{
    SettingA=1,
    SettingB=2,
    SettingC=4,
    SettingD=8
}

class Program
{
    static void Main(string[] args)
    {
        var settingsFlags1 = MySettings.SettingA | MySettings.SettingB;
        var settingsFlags2 = MySettings.SettingB | MySettings.SettingC | MySettings.SettingD;


        int mySettings1 = (int)settingsFlags1;
        int mySettings2 = (int)settingsFlags2;

        Console.WriteLine("Analyse mySetting1");
        AnalyseSettings(mySettings1);
        Console.WriteLine("Analyse mySetting2");
        AnalyseSettings(mySettings2);

        Console.ReadKey();
    }

    private static void AnalyseSettings(int mySettings)
    {
// ...
    }
}

【讨论】:

  • 当然。这意味着尽管我必须为每种可能的组合戴一个面具,对吗?并且没有特别的理由使用移位运算符。它使我更容易阅读,您查看移位量,并且您知道哪个位被映射到该枚举值。无需弄清楚它是否是第 8 位的第 7 位。
  • 如果它适合你,你可以从最低位开始。您需要什么样的口罩取决于您的具体情况。如果这是一个常见的场景,为什么不呢?在我以前的工作中,我需要为每个位设置一个掩码来确定我们的硬件设备的状态(找到卡、打开电源等)并且效果很好
猜你喜欢
  • 1970-01-01
  • 2022-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 1970-01-01
  • 2011-05-01
相关资源
最近更新 更多