【问题标题】:Large flags enumerations in C#C# 中的大型标志枚举
【发布时间】:2011-02-17 00:54:06
【问题描述】:

大家好,有一个快速的问题,我似乎找不到任何关于...的信息。

我正在处理一个需要带有大量标志(最多 40 个)的标志枚举的项目,我真的不想为每个枚举值输入确切的掩码:

public enum MyEnumeration : ulong
{
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
    Flag4 = 8,
    Flag5 = 16,
    // ...
    Flag16 = 65536,
    Flag17 = 65536 * 2,
    Flag18 = 65536 * 4,
    Flag19 = 65536 * 8,
    // ...
    Flag32 = 65536 * 65536,
    Flag33 = 65536 * 65536 * 2
    // right about here I start to get really pissed off
}

此外,我还希望有一种简单(更)的方法来控制不同字节序机器上位的实际排列,因为这些值最终将通过网络进行序列化:

public enum MyEnumeration : uint
{
    Flag1 = 1,     // BIG: 0x00000001, LITTLE:0x01000000
    Flag2 = 2,     // BIG: 0x00000002, LITTLE:0x02000000
    Flag3 = 4,     // BIG: 0x00000004, LITTLE:0x03000000
    // ...
    Flag9 = 256,   // BIG: 0x00000010, LITTLE:0x10000000
    Flag10 = 512,  // BIG: 0x00000011, LITTLE:0x11000000
    Flag11 = 1024  // BIG: 0x00000012, LITTLE:0x12000000
}

所以,我有点想知道是否有一些很酷的方法可以设置我的枚举,例如:

public enum MyEnumeration : uint
{
     Flag1 = flag(1), // BOTH: 0x80000000
     Flag2 = flag(2), // BOTH: 0x40000000
     Flag3 = flag(3), // BOTH: 0x20000000
     // ...
     Flag9 = flag(9), // BOTH: 0x00800000
}

我的尝试:

// this won't work because Math.Pow returns double
// and because C# requires constants for enum values
public enum MyEnumeration : uint
{
    Flag1 = Math.Pow(2, 0),
    Flag2 = Math.Pow(2, 1)
}

// this won't work because C# requires constants for enum values
public enum MyEnumeration : uint
{
    Flag1 = Masks.MyCustomerBitmaskGeneratingFunction(0)
}

// this is my best solution so far, but is definitely
// quite clunkie
public struct EnumWrapper<TEnum> where TEnum
{
    private BitVector32 vector;
    public bool this[TEnum index]
    {
         // returns whether the index-th bit is set in vector
    }
    // all sorts of overriding using TEnum as args
}

只是想知道是否有人有任何好主意,谢谢!

【问题讨论】:

  • 您在这里输入了几百行文字。你为什么不硬着头皮输入原来的 40 行呢? (您可能使用了 1
  • 嗯...我确实想展示我尝试过的解决方案,“>”会起作用,但我并没有完全看到它们仅评估时的区别一次。不是半个小时就能打出来的,几百行也不算多……我宁愿提供太多信息也不要太少……
  • 您可以使用移位运算符的完整范围的 ulong,您只需向编译器指示您正在移位的 1 是一个 ulong。 1ul

标签: c# enumeration endianness flags


【解决方案1】:

像这样使用 1UL

[Flags]    
    public enum EventType : ulong
    {
        f1= 1,
        f2= 1 << 1,
        f3= 1 << 2,
        ......

        f... = 1 << 30,
        f... = 1UL << 31,
        f...  = 1UL << 32        
    }

【讨论】:

  • 这是迄今为止最容易实现和使用的解决方案。不知道为什么它没有更多的选票。
【解决方案2】:

您可以编写一个 T4 模板来生成枚举:

模板 (MyEnumeration.tt)

<#@ template language="C#" #>
<#@ output extension=".cs" #>
using System;

namespace MyNamespace
{
    [Flags]
    public enum MyEnumeration : ulong
    {
<#
    ulong value = 1;
    for(int i = 1; i <= 64; i++)
    {
#>
        Flag<#= i #> = <#= string.Format("0x{0:X8}", value) #>,
<#
        value = value << 1;
    }
#>
    }
}

生成的 C# 代码 (MyEnumeration.cs)

using System;

namespace MyNamespace
{
    [Flags]
    public enum MyEnumeration : ulong
    {
        Flag1 = 0x00000001,
        Flag2 = 0x00000002,
        Flag3 = 0x00000004,
        Flag4 = 0x00000008,
        Flag5 = 0x00000010,
        Flag6 = 0x00000020,
        Flag7 = 0x00000040,
        Flag8 = 0x00000080,
        Flag9 = 0x00000100,
        Flag10 = 0x00000200,
        Flag11 = 0x00000400,
        Flag12 = 0x00000800,
        Flag13 = 0x00001000,
        Flag14 = 0x00002000,
        Flag15 = 0x00004000,
        Flag16 = 0x00008000,
        Flag17 = 0x00010000,
        Flag18 = 0x00020000,
        Flag19 = 0x00040000,
        Flag20 = 0x00080000,
        Flag21 = 0x00100000,
        Flag22 = 0x00200000,
        Flag23 = 0x00400000,
        Flag24 = 0x00800000,
        Flag25 = 0x01000000,
        Flag26 = 0x02000000,
        Flag27 = 0x04000000,
        Flag28 = 0x08000000,
        Flag29 = 0x10000000,
        Flag30 = 0x20000000,
        Flag31 = 0x40000000,
        Flag32 = 0x80000000,
        Flag33 = 0x100000000,
        Flag34 = 0x200000000,
        Flag35 = 0x400000000,
        Flag36 = 0x800000000,
        Flag37 = 0x1000000000,
        Flag38 = 0x2000000000,
        Flag39 = 0x4000000000,
        Flag40 = 0x8000000000,
        Flag41 = 0x10000000000,
        Flag42 = 0x20000000000,
        Flag43 = 0x40000000000,
        Flag44 = 0x80000000000,
        Flag45 = 0x100000000000,
        Flag46 = 0x200000000000,
        Flag47 = 0x400000000000,
        Flag48 = 0x800000000000,
        Flag49 = 0x1000000000000,
        Flag50 = 0x2000000000000,
        Flag51 = 0x4000000000000,
        Flag52 = 0x8000000000000,
        Flag53 = 0x10000000000000,
        Flag54 = 0x20000000000000,
        Flag55 = 0x40000000000000,
        Flag56 = 0x80000000000000,
        Flag57 = 0x100000000000000,
        Flag58 = 0x200000000000000,
        Flag59 = 0x400000000000000,
        Flag60 = 0x800000000000000,
        Flag61 = 0x1000000000000000,
        Flag62 = 0x2000000000000000,
        Flag63 = 0x4000000000000000,
        Flag64 = 0x8000000000000000,
    }
}

为了编辑 T4 模板,我建议您使用 T4 编辑器插件,如 this one(这为您提供语法高亮和智能感知)

【讨论】:

  • 您几乎不需要 T4 系统来执行此操作。任何脚本编程语言中的一个简单循环都可以打印出它的核心。
  • 是的,但是Visual Studio中内置了T4,这使得这种事情非常方便......
  • 不错。 64以上有可能吗?
  • @arao6,没有。为此,您需要一个超过 64 位的整数类型……但没有(当然有 BigInteger,但它不能用于枚举)
【解决方案3】:

为什么不直接做:

public enum MyEnumeration : ulong 
{ 
    Flag1 = 1, 
    Flag2 = 1 << 1, 
    Flag3 = 1 << 2, 
    Flag4 = 1 << 3, 
    .
    .
    .
    Flag30 = 1 << 29, 
    Flag31 = 1 << 30, 
    Flag32 = 1 << 31
}

【讨论】:

  • hmm... 8 位后面的位移对我来说似乎很奇怪... 我不确定编译器是否会自动处理这个问题,但从技术上讲,不应该 (1
  • @LorenVS,您可以使用 ulong 的全部范围和移位运算符,您只需要向编译器指示您要移位的 1 是一个 ulong。 1ul
  • @LorenVS - 编译器对此很好。但是,它被包装到数据大小。所以实际上对于int/Int32,1 ulong 在这种情况下它是 % 64,所以 1
【解决方案4】:

为了解决字节序问题,你有两个我能想到的选项

1- 自行处理序列化并使用 System.Net.IPAddress.HostToNetworkOrder 确保在线上一致的字节顺序,当然在反序列化时使用 System.Net.IPAddress.NetworkToHostOrder 进行相反的操作。

我有两篇关于二进制序列化主题的旧博客文章,它们可以更新,但这是一个起点。

http://taylorza.blogspot.com/2010/04/archive-binary-data-from-structure.html
http://taylorza.blogspot.com/2010/04/archive-structure-from-binary-data.html

2- 序列化为 XML,在这种情况下字节序不是问题,但当然还有其他缺点,例如有效负载大小和一般性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-14
    • 2010-12-10
    相关资源
    最近更新 更多