2011-08-04 101 views
3

枚举位字段我这个问题的标题道歉,但我想不出更好的方式来描述一下我试图完成..支持继承

我想用做一个枚举Flags属性,枚举的按位值创建一些继承模式。

示例:假设我们有食物的位域枚举:

[Flags] 
enum Foods 
{ 
    // Top Level foods 
    Meat, 
    Fruit, 
    Vegetables, 
    Dairy, 
    Grain, 
    BenJerrysOatmealCookieChunk, // ;) 

    // sub-Meat 
    Chicken, 
    Beef, 
    Fish, 

    // sub-Fruit 
    Apple, 
    Banana, 

    // sub-Vegetables 
    Spinach, 
    Broccoli, 

    // sub-Dairy 
    Cheese, 
    Milk, 

    // sub-Grain 
    Bread, 
    Pasta, 
    Rice, 

    // sub-Beef 
    Tritip, 
    Hamburger, 

    // sub-Fish 
    Salmon, 
    Halibut,  
} 

注意枚举如何包含食品的子类以及子子类别。 在我的现实世界中,我有一个未知数量的顶级类别和未知数量的子级别类别(包括未知级别的子子类别n)

我会喜欢设置枚举的位值,使得子类别(和子子类别n)将“继承”其直接父级的位值。

我想避免Foods属性的客户端设置者必须明确设置特定食物的所有标志。换句话说,我不希望客户制定者不得不做这样的事情:

myClass.Foods = Foods.Tritip | Foods.Beef | Foods.Meat; 

我想创建一个结构,使得客户端制定者只需简单地设置一个标志和标志的所有家长都隐含在子标志内。

因此,如果客户端二传手这样做:

myClass.Foods = Foods.Tritip; 

我们将能够成功运行以下条件:

if((myClass.Foods & Foods.Meat) == Foods.Meat) 
Console.WriteLine("I am meat"); 

if((myClass.Foods & Foods.Beef) == Foods.Beef) 
Console.WriteLine("I am beef"); 

if((myClass.Foods & Foods.Tritip) == Foods.Tritip) 
Console.WriteLine("I am tritip"); 

if((myClass.Foods & Foods.Meat) == Foods.Meat) 
Console.WriteLine("I am meat"); 

if((myClass.Foods & Foods.Rice) != Foods.Rice) 
Console.WriteLine("I am definitely not rice!"); 

什么混淆了我对这个问题是什么比特值以用于enum中的每个食物。我最初开始了:

[Flags] 
    enum Foods 
    { 
     // Top Level foods 
     Meat = 0x1, 
     Fruit = 0x2, 
     Vegetables = 0x4, 
     Dairy = 0x8, 
     Grain = 0x10, 
     BenJerrysOatmealCookieChunk = 0x20, // ;) 

     ...and so on. 
    } 

..但因为我不知道有多少水平会有(枚举名单将随时间增长)。我不知道如何创建我的位值所以他们允许增长。

有没有人试图做到这一点?如果是这样,你的位值的业务逻辑是什么?

我有一个偷偷摸摸的感觉,这个问题将需要一个赏金;)

+1

我不会打出来的房子获得本杰里上午2:30 。 – BoltClock

+0

当你知道你可以有任意数量的元素时,试图用枚举来做这件事实在太疯狂了。我们大多数人使用相互之间具有层次关系的元素树,通常存储在关系数据库或XML中。 'myclass.HasAncestorCategory(“肉”)'更容易。 –

回答

3

OP说(我引述)

注意枚举如何包含食品的子类以及子子类别。 在我的现实世界中,我有一个未知数量的顶级类别和一个未知数量的子级别类别(包括未知级别的 子子类型的子类别)。

然后你没有枚举:你有某种类型的层次结构。枚举(按设计)包装某种整数类型并具有固定数量的元素。事实上,它们基本上是定点整数,它提供了可用位数的上限:枚举的大小为8,16,32或64位。

鉴于这些限制枚举,您可以执行类似以下操作(并且您不需要或不需要[Flags]属性)。在下面的例子中,我为“类别”保留了32位,“子类别”保留了32位。

enum Foods : ulong 
{ 
    CategoryMask    = 0xFFFFFFFF00000000 , 


    // Top Level foods 
    Meat      = 0x0000000100000000 , 
    Fruit      = 0x0000000200000000 , 
    Vegetables     = 0x0000000400000000 , 
    Dairy      = 0x0000000800000000 , 
    Grain      = 0x0000001000000000 , 
    BenJerrysOatmealCookieChunk = 0x0000002000000000 , // ;) 

    Chicken = Meat   | 0x0000000000000001 , 
    Beef  = Meat   | 0x0000000000000002 , 
    Fish  = Meat   | 0x0000000000000004 , 
    Apple  = Fruit   | 0x0000000000000001 , 
    Banana = Fruit   | 0x0000000000000002 , 
    Spinach = Vegetables  | 0x0000000000000001 , 
    Broccoli = Vegetables  | 0x0000000000000002 , 
    Cheese = Dairy   | 0x0000000000000001 , 
    Milk  = Dairy   | 0x0000000000000002 , 
    Bread  = Grain   | 0x0000000000000001 , 
    Pasta  = Grain   | 0x0000000000000002 , 
    Rice  = Grain   | 0x0000000000000004 , 
    TriTip = Beef   | 0x0000000000000001 , 
    Hamburger = Beef   | 0x0000000000000002 , 
    Salmon = Fish   | 0x0000000000000004 , 
    Halibut, = Fish   | 0x0000000000000008 , 
} 

注意询问其类别将一个Foods值需要一定的位操作,像这样:

Foods item  = Foods.Hamburger ; 
Foods category = (Foods) ((ulong)item & (ulong)Foods.CategoryMask) ; 
1

这是不可能的。枚举不能从其他枚举继承。事实上,所有枚举实际上都必须从System.Enum继承。 C#允许语法改变看起来像继承的枚举值的底层表示,但实际上它们仍然继承于System.enum。

有关详细信息,请参阅CLI规范的第8.5.2节。从规范的相关信息

  • 所有枚举必须从System.Enum派生由于上述的
  • ,所有枚举是值类型,因此密封

你可以,但是,实现你想要的带有基类和派生类。

+0

仅供参考 - 我不想继承枚举类型。我试图继承按位值。 “继承”在这种情况下是一个误导性的术语,但它确实描述了我的意图。示例:((0x2&0x12)==(0x2))计算结果为true时,按位值0x12“继承”0x2。 – Jed

6

你可以通过在枚举声明本身内部按位或OR来做到这一点。虽然这不会给你一个干净的ToString就像你通常会得到与标志属性,它确实给你所期望的结果:

[Flags] 
public enum Foods : ulong 
{ 
    Meat = 0x100000, 
    Fruit = 0x200000, 
    Vegetables = 0x400000, 
    Dairy = 0x800000, 
    Grain = 0xF00000, 

    Beef = Meat | 0x100, 
    Chicken = Meat | 0x200, 
    Fish = Meat | 0x400, 

    Apple = Fruit | 0x100, 
    Banana = Fruit | 0x200, 

    Spinach = Vegetables | 0x100, 
    Broccoli = Vegetables | 0x200, 

    Cheese = Dairy | 0x100, 
    Milk = Dairy | 0x200, 

    Bread = Grain | 0x100, 
    Pasta = Grain | 0x200, 
    Rice = Grain | 0x400, 

    Tritip = Beef | 0x1, 
    Hamburger = Beef | 0x2, 

    Salmon = Fish | 0x100, 
    Halibut = Fish | 0x200, 
} 

我用ULONG为枚举的基础,使您得到子类别更多的空间。我并没有从最高阶位开始,但如果我是你,我会尽可能地留出空间去表现更深的类别。此外,您还需要充分利用子类别之间的间隔来获得最佳结果。