2010-05-07 16 views
13

Cześć wszystkim, mam szybkie pytanie, że nie mogę znaleźć nic na temat ...Duże flagi wyliczenia w C#

pracuję nad projektem, który wymaga wyliczeń flaga z dużą liczbą flag (do 40-owski), a ja naprawdę nie czuję się jak pisać w dokładnym maski dla każdej wartości liczby:

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 
} 

Ponadto, mam też nadzieję, że nie jest to łatwe (ier) sposób dla mnie do kontrolowania aktualnego rozmieszczenia bitów na różnych maszynach endian, ponieważ te wartości będą ostatecznie serializowane przez sieć:

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 
} 

Więc ja niby zastanawiać, czy istnieje jakiś fajny sposób mogę ustawić moich wyliczeń w górę jak:

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

Co Próbowałem:

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

Wystarczy zastanawiasz się, czy ktoś ma jakieś fajne pomysły, dzięki!

+3

wpisałeś kilkaset wierszy tekstu tutaj. Dlaczego po prostu nie ugryzłeś kuli i nie wpisałeś oryginalnych 40 linii? (Mógłbyś użyć 1 << 1, 1 << 2, ... zamiast mnożenia, ale tak czy inaczej ...) –

+0

Umm ... Chciałem przedstawić rozwiązania, które próbowałem, "<<" and ">>" pracował, ale nie widzę różnicy, gdy są one oceniane tylko raz. To nie tak, że zajmuje mi to pół godziny, a kilkaset linii tekstu to niewiele ...Wolałbym podać zbyt dużo informacji niż za mało ... – LorenVS

+1

możesz użyć pełnego zakresu ulong z operatorem zmiany, po prostu musisz wskazać kompilatorowi, że 1, którego przesuwasz, jest ulong. 1ul << 63, zwróć uwagę na "ul" po 1. –

Odpowiedz

9

można napisać szablon T4 do generowania ENUM:

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

wygenerowany kod 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, 
    } 
} 

W celu edycji szablonów T4, polecam użyć wtyczki edytor T4 jak this one (daje to podświetlanie składni i Intellisense)

+0

Do tego celu nie potrzebujesz systemu T4. Prosta pętla w dowolnym języku programowania skryptowego może wydrukować rdzeń tego. –

+0

Tak, ale T4 wbudowany w Visual Studio, co sprawia, że ​​jest to bardzo wygodne dla tego rodzaju rzeczy ... –

+0

Nice. Czy można przekroczyć 64? – arao6

0

Dobrze zająć się endianes masz dwie opcje, które mogę myśleć poza czubek głowy

1- Klamka serializacji siebie i wykorzystywać w celu zapewnienia spójnego System.Net.IPAddress.HostToNetworkOrder bajt zamawiania na Drut i oczywiście wykonaj odwrotne działanie z System.Net.IPAddress.NetworkToHostOrder po deserializacji.

Mam dwa stare posty na blogu na temat serializacji binarnej, mogą zrobić z aktualizacją, ale to jest punkt wyjścia.

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- Serializować do XML, w którym to przypadku endianes nie jest problemem, ale oczywiście istnieją inne wady, takie jak wielkość ładunku i ogólnej wydajności.

9

Dlaczego nie po prostu zrobić:

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 ... przesuwanie bitów za 8 bitami wydaje mi się dziwne ... Nie jestem pewien, czy kompilator obsługuje to automatycznie, ale technicznie, nie powinien (1 << 8) == 0 niezależnie od wielkości typu danych na małych systemach endianowych? Mogę być całkowicie na lunch, nie jestem pewien – LorenVS

+7

@LorenVS, możesz użyć pełnego zakresu ulong z operatorem zmiany, po prostu musisz wskazać kompilatorowi, że 1, którego przesuwasz, jest ulong. 1ul << 63, zauważ 'ul' afer 1. –

+3

@LorenVS - Kompilator jest w porządku z tym. Jest jednak zawinięty do rozmiaru danych. Tak więc dla 'int' /' Int32', 1 << 33 jest takie samo jak 1 << 1. Ponieważ (zauważmy jednak komentarz Chris'a) używamy 'ulong' w tym przypadku jest to% 64, więc 1 < <65 jest takie samo jak 1 << 1 –