2010-05-07 3 views
13

Привет всем, есть быстрый вопрос, который я не могу найти ничего о ...Большие флаги перечислений в C#

Я работаю над проектом, который требует перечислений флаг с большим количеством флагов (до 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 
} 

Просто интересно, есть ли у кого-нибудь интересные идеи, спасибо!

+3

Вы набрали несколько сотен строк текста здесь. Почему вы просто не укусили пулю и не набрали оригинальные 40 строк? (Возможно, вы использовали 1 << 1, 1 << 2, ... вместо множителей, но в любом случае ...) –

+0

Умм ... Я действительно хотел представить решения, которые я пробовал, «<<" and ">>» имел бы но я точно не вижу разницы, когда их оценивают только один раз. Это не похоже на то, что мне требуется полчаса, чтобы напечатать это, несколько сотен строк текста не так много ...Я бы предпочел предоставить слишком много информации, чем слишком мало ... – LorenVS

+1

вы можете использовать весь диапазон ulong с оператором shift, вам просто нужно указать компилятору, что 1, который вы перемещаете, является ulong. 1ul << 63, обратите внимание на 'ul' afer the 1. –

ответ

9

Вы могли бы написать шаблон 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 (это дает подсветку синтаксиса и Intellisense)

+0

Для этого вам вряд ли нужна система T4. Простой цикл на любом языке программирования сценариев может печатать ядро ​​этого. –

+0

Да, но T4 встроен в Visual Studio, что делает его очень удобным для такого рода вещей ... –

+0

Nice. Можно ли пройти выше 64? – arao6

0

Ну для решения endianes у вас есть два варианта, которые я могу думать с верхней частью моей головы

1- Обрабатывать сериализациям себя и использовать System.Net.IPAddress.HostToNetworkOrder для обеспечения последовательных байт заказа на провод и, конечно же, сделать обратное с System.Net.IPAddress.NetworkToHostOrder, когда вы deserialize.

У меня есть две старые сообщения в блогах по теме двоичной сериализации, они могут делать с обновлением, но это отправная точка.

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, и в этом случае endianes не является проблемой, но, конечно, есть и другие недостатки, такие как размер полезной нагрузки и общей производительности.

9

Почему бы не просто сделать:

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 ... бит сдвигается за 8 бит, кажется мне странным ... Я не уверен, что компилятор обрабатывает это автоматически, но технически, не должен (1 << 8) == 0 независимо от размера типа данных в системах с маленькими концами? Я могу быть полностью обеденным, я не уверен – LorenVS

+7

@LorenVS, вы можете использовать весь диапазон ulong с оператором shift, вам просто нужно указать компилятору, что 1, который вы переставляете, является ulong. 1ul << 63, обратите внимание на 'ul' afer the 1. –

+3

@LorenVS - компилятор в порядке с этим. Это, однако, завернуто в размер данных. Так что фактически для 'int' /' Int32', 1 << 33 совпадает с 1 << 1. Так как (отметим комментарий Криса, хотя), мы используем 'ulong', в этом случае это% 64, поэтому 1 < <65 совпадает с 1 << 1 –

Смежные вопросы