2010-05-07 23 views
13

Hola a todos, tengo una pregunta rápida que me parece que no puede encontrar nada sobre ...banderas grandes enumeraciones en C#

Estoy trabajando en un proyecto que requiere enumeraciones, marca con un gran número de banderas (hasta el 40-ish), y no me siento muy similar a hacerlo en la máscara exacta para cada valor de la enumeración:

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 
} 

por otra parte, también estoy esperando que hay una (IER) forma fácil para mí para controlar la disposición real de los bits en diferentes máquinas Endian, ya que estos valores se serializarán eventualmente a través de una red:

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 
} 

Por lo tanto, estoy un poco pregunto si hay alguna manera fresca puedo configurar mis enumeraciones arriba como:

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

lo que he intentado:

// 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 
} 

Justo preguntándose si alguien tiene ideas geniales, ¡gracias!

+3

que ha escrito unos pocos cientos de líneas de texto aquí. ¿Por qué no acabas de morder la bala y tecleas las 40 líneas originales? (Es posible que haya utilizado 1 << 1, 1 << 2, ... en lugar de las multiplicaciones, pero de todos modos ...) –

+0

Umm ... Yo quería presentar las soluciones que había intentado, "<<" and ">>" habría funcionó, pero no veo exactamente la diferencia cuando solo se evalúan una vez. No es como que me tome media hora escribir esto, unos pocos cientos de líneas de texto no son muchas ...Prefiero proporcionar demasiada información que muy poco ... – LorenVS

+1

puede usar todo el rango del ulong con el operador de desplazamiento, solo tendrá que indicar al compilador que el 1 que está cambiando es un ulong. 1ul << 63, fíjate en el 'ul' después del 1. –

Respuesta

9

Se podría escribir una plantilla T4 para generar la enumeración:

Plantilla (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; 
    } 
#> 
    } 
} 

resultante de código 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, 
    } 
} 

Con el fin de editar plantillas T4, le recomiendo que utilice un plug-in editor de T4 como this one (esto le da resaltado de sintaxis y Intellisense)

+0

Casi no necesita un sistema T4 para hacer esto. Un simple bucle en cualquier lenguaje de programación de scripting puede imprimir el núcleo de esto. –

+0

Sí, pero T4 está integrado en Visual Studio, lo que lo hace muy conveniente para ese tipo de cosas ... –

+0

Nice. ¿Es posible ir por encima de 64? – arao6

0

bien para hacer frente a los endianes tiene dos opciones que puedo pensar en la parte superior de mi cabeza

1- Manejar la serialización de su auto y utilizar System.Net.IPAddress.HostToNetworkOrder para asegurar byte consistente en ordenar el cable y, por supuesto, haga lo contrario con System.Net.IPAddress.NetworkToHostOrder cuando se deserialice.

Tengo dos entradas de blog antiguas sobre el tema de la serialización binaria, que podrían hacer con una actualización, pero es un punto de partida.

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- Serialize a XML, en cuyo caso endianes no es un problema, pero por supuesto hay otras desventajas tales como el tamaño de carga útil y el rendimiento general.

9

¿Por qué no hacer:

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

hmm ... el bit que se mueve detrás de 8 bits me parece extraño ... No estoy seguro si el compilador maneja esto automáticamente, pero técnicamente no debería (1 << 8) == 0 independientemente del tamaño del tipo de datos en pequeños sistemas endian? Puede que salga completamente a almorzar, no estoy seguro – LorenVS

+7

@LorenVS, puede usar el rango completo del ulong con el operador de desplazamiento, solo tendrá que indicar al compilador que el 1 que está cambiando es un ulong. 1ul << 63, observe el 'ul' después del 1. –

+3

@LorenVS - El compilador está de acuerdo con eso. Sin embargo, está ajustado al tamaño de datos. Así que en realidad para 'int' /' Int32', 1 << 33 es lo mismo que 1 << 1. Desde (note el comentario de Chris, sin embargo) estamos usando 'ulong' en este caso es% 64, entonces 1 < <65 es lo mismo que 1 << 1 –