【问题标题】:Indexing a BitArray where bits are defined by a generic Enum索引位由通用枚举定义的位数组
【发布时间】:2013-08-16 16:19:57
【问题描述】:

我正在从医疗设备中提取字节流,但遇到了一个非常烦人的数据结构。基本上,我得到了一个 2 字节的块,其中每个位代表一个布尔值。这种结构在字节流中出现得足够频繁,可以围绕它开发一个结构/类,但在每种情况下,位的含义完全不同。

所以首先我设置了一堆枚举来表示位结构可能具有的所有不同定义。 (请注意,并非每个定义都使用每个位。有时重要位之间会有中断。)

编辑:删除了所有看起来像“标志”的名称。我没有使用 [Flags] 属性,这似乎是一个争论点/混淆点。枚举值只是映射到我的 BitArray 中的索引。

public enum RecordInfo { AM_TEST = 0, PM_TEST, TEST_VALIDITY };
public enum RecordAlerts { ALERT1 = 0, ALERT2, ALERT3, ALERT4, VALIDATED = 15 };

然后创建这个容器来保存实际的位:

public struct TwoBytes<TEnum> where TEnum : struct, IConvertible
{
    private BitArray _bits = new BitArray(2);
}

这似乎可以按我的需要工作,直到我想根据 Enum 名称索引我的结构。假设我有一个名为 Alerts 的 TwoByte 结构,它包含一些位值。如果我想获得这样的特定标志:

bool alert3Set = Alerts[RecordAlerts.ALERT3]

我最终得到了一个真正令人发指的索引函数。这就是我现在所拥有的:

public bool this[TEnum name]
{
    get
    {
        int index = Enum.GetValues(typeof(TEnum)).Cast<TEnum>().ToList().Where(x => x.Equals(name)).Cast<int>().First();
        return _bits[index];
    }
}

现在它可以工作了,太疯狂了。但是 LINQ 链看起来确实很糟糕,并且需要一段时间才能破译它实际上在做什么。

有没有一种更简洁、更有效的方法将通用枚举“名称”转换为其整数值?还是我更适合使用字典(或其他对象)来表示位结构定义?

【问题讨论】:

  • 虽然这是一个看似不错的问题,但由于您说它有效并且没有错误,这似乎更像是Code Review 的问题。
  • 您是否有理由不为枚举使用 [Flags] 注释,而是直接使用像 { FLAG1 = 1, FLAG2 = 2, FLAG3 = 4, FLAG4 = 8 } 这样的位掩码,其值为 2 的幂?
  • 这个问题确实有问题。这些枚举缺少 [Flags] 属性。 RecordFlags 类型的值永远不能明确存储多个 一个 标志。 Enum.GetName() 已经解决了这个问题。
  • @Hans Passant 我不熟悉 [Flags] 属性。事实上,我的枚举最终使用了 Flags 这个词,这完全是无意的。
  • 好吧,没有人会阻止你看看你最喜欢的 C# 语言书籍。但是当您编写代码时,Enum.GetName() 就是您所需要的。

标签: c# generics enums


【解决方案1】:

只要您使用的每个 TEnum 都派生自 int(默认值),而不是其他数字类型,这将起作用:

public bool this[TEnum name]
{
    get
    {
        int index = (int)(object)name;
        return _bits[index];
    }
}

如果您想支持从较小类型派生的enums(以及仅使用int 支持的范围内的值的枚举),我会使用:

public bool this[TEnum name]
{
    get
    {
        int index = Convert.ToInt32(name);
        return _bits[index];
    }
}

(完全支持从无法隐式转换为int 的类型派生的枚举,例如uintlongulong,变得更加复杂,因为BitArray 的索引器使用@ 987654332@)

【讨论】:

  • 哇... (int)(object)name 完全取代了我可怕的 LINQ 链。这是令人谦卑的。谢谢。
  • @MadHenchbot 过度思考发生在我们当中。 :)
【解决方案2】:

我认为一点 OOP 会让您的生活更轻松。您可以引入代表您收到的数据的类,并具有有意义的属性名称。每个类都可以将您的 BitArray 接受到构造函数中并将其解析为属性。

在您的程序中,您可以使用这些类而不是摆弄位。

【讨论】:

  • 我正在将其结果进一步转换为结构化类,但在这个数据层中,我正在以一种非常通用的方式读取字节,即:Read(int size)。我允许 T 接受的东西越少越好。仍然是一个有效的答案。
【解决方案3】:

正如 FrankPI 在 cmets 中建议的那样,为什么不使用 enum 其值真正代表每个位,而不是使用中间 BitArray

[Flags]
public enum RecordFlags { FLAG1 = 0x1, FLAG2 = 0x2, FLAG3 = 0x4, FLAG4 = 0x8, FLAG5 = 0x10, VALIDATED = 0x8000 };

var readFlags = (RecordFlags) ((bytes[0] << 8) | bytes[1]);
bool hasFlag2 = (readFlags & RecordFlags.Flag2) != 0;

【讨论】:

  • 非常酷!老实说,我不知道我可以做这样的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-09
  • 2010-09-29
  • 1970-01-01
相关资源
最近更新 更多