2010-05-07 19 views
13

Ciao a tutti, ha ottenuto una domanda veloce che io non riesco a trovare nulla ...grandi bandiere enumerazioni in C#

Sto lavorando su un progetto che richiede enumerazioni bandiera con un gran numero di bandiere (fino al 40-ish), e non mi sento davvero come digitando nella maschera esatta per ciascun valore di enumerazione:

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 
} 

inoltre, sto anche sperando che non v'è un facile (ier) modo per me per controllare l'effettiva disposizione dei bit su diverse macchine endian, dal momento che questi valori saranno eventualmente serializzati su una rete:

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 
} 

Quindi, sto tipo di chiedevo se c'è un modo fresco posso impostare il mio enumerazioni in su come:

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

che cosa ho provato:

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

Proprio chiedendo se qualcuno ha qualche idea interessante, grazie!

+3

avete digitato poche centinaia di righe di testo qui. Perché non hai appena morso il proiettile e hai digitato le 40 linee originali? (Potresti aver usato 1 << 1, 1 << 2, ... invece dei multipli, ma comunque ...) –

+0

Umm ... Volevo presentare le soluzioni che avevo provato, "<<" and ">>" avrebbe ha funzionato, ma non vedo esattamente la differenza quando vengono valutati solo una volta. Non è che mi ci voglia mezz'ora per scrivere questo, poche centinaia di righe di testo non sono molte ...Preferirei fornire troppe informazioni che troppo poco ... – LorenVS

+1

puoi usare l'intera gamma di ulong con l'operatore del cambio, dovrai solo indicare al compilatore che il 1 che stai spostando è un ulong. 1ul << 63, notate che l''ul' più basso è il 1. –

risposta

9

Si potrebbe scrivere un modello T4 per generare l'enumerazione:

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

risultante codice 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, 
    } 
} 

Al fine di modificare i modelli T4, vi consiglio di utilizzare un plugin editor di T4 come this one (questo ti dà l'evidenziazione della sintassi e Intellisense)

+0

Non è necessario un sistema T4 per farlo. Un semplice ciclo in qualsiasi linguaggio di programmazione di script può stampare il nucleo di questo. –

+0

Sì, ma T4 è integrato in Visual Studio, il che lo rende molto conveniente per questo genere di cose ... –

+0

Nice. È possibile andare sopra i 64? – arao6

0

Bene per affrontare le endianes si hanno due opzioni che mi viene in mente la parte superiore della mia testa

1- Maneggiare la serializzazione vostra auto e utilizzare System.Net.IPAddress.HostToNetworkOrder per garantire byte consistente ordinare su il filo e, naturalmente, si fa il contrario con System.Net.IPAddress.NetworkToHostOrder quando si deserializza.

Ho due vecchi post del blog sull'argomento della serializzazione binaria, potrebbero fare con un aggiornamento ma è un punto di partenza.

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- serializzare XML, nel qual caso endianes non è un problema, ma naturalmente ci sono altri aspetti negativi quali le dimensioni del carico utile e le prestazioni generali.

9

Perché non basta fare:

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 ... il bit shifting dietro 8 bit mi sembra strano ... Non sono sicuro che il compilatore lo gestisca automaticamente, ma tecnicamente, non dovrebbe (1 << 8) == 0 indipendentemente dalla dimensione del tipo di dati sui sistemi little endian? Potrei essere completamente fuori a pranzo, non sono sicuro – LorenVS

+7

@LorenVS, è possibile utilizzare l'intera gamma di ulong con l'operatore di turno, sarà solo necessario indicare al compilatore che il 1 che si sta spostando è un ulong. 1ul << 63, notate che il 'ul' è il 1. –

+3

@LorenVS - Il compilatore sta bene con quello. È, tuttavia, avvolto nella dimensione dei dati. Quindi in realtà per 'int' /' Int32', 1 << 33 è lo stesso di 1 << 1. Poiché (si noti il ​​commento di Chris, però) stiamo usando 'ulong' in questo caso è% 64, quindi 1 < <65 è lo stesso di 1 << 1 –