C# 枚举支持继承的位字段

C# 枚举支持继承的位字段,c#,inheritance,enums,bit-manipulation,bit,C#,Inheritance,Enums,Bit Manipulation,Bit,对于这个问题的标题,我深表歉意,但我想不出更好的方式来描述我正在努力实现的目标 我想使用Flags属性创建一个枚举,通过该属性,枚举的按位值可以创建某种继承模式 示例:假设我们有一个食物的位字段枚举: [Flags] enum Foods { // Top Level foods Meat, Fruit, Vegetables, Dairy, Grain, BenJerrysOatmealCookieChunk, // ;) //

对于这个问题的标题,我深表歉意,但我想不出更好的方式来描述我正在努力实现的目标

我想使用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类)

我希望设置枚举的位值,以便子类别(和sub-sub-n-categories)将“继承”其直接父级的位值

我希望避免Foods属性的客户端设置程序必须显式地设置特定食物的所有标志。换句话说,我不希望客户端setter必须执行以下操作:

myClass.Foods = Foods.Tritip | Foods.Beef | Foods.Meat;
我试图创建一个构造,以便客户端setter只需设置一个标志,并且该标志的所有父项都隐式地包含在子标志中

因此,如果客户机setter这样做:

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!");
关于这个问题,让我困惑的是枚举中每个食物项使用什么位值。我最初是从以下方面开始的:

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

        ...and so on.
     }
。。但由于我不知道会有多少级别(枚举列表将随着时间的推移而增长)。。我不知道如何创建我的比特值,以便它们允许增长

以前有人尝试过这样做吗?如果是的话,您的比特值的业务逻辑是什么


我隐约觉得这个问题需要悬赏;)

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

有关完整详细信息,请参见CLI规范第8.5.2节。规范中的相关信息

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

但是,您可以使用基类和派生类实现所需的功能。

您可以通过按位或在枚举声明本身内部执行来实现这一点。虽然这不会像通常使用Flags属性时那样为您提供一个干净的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作为枚举的基础,以便为子类别获得更多空间。我并没有尽可能从最高级别开始,但如果我是你,我会这样做,这样就有空间来代表更深层的类别。此外,您还需要调整子类别之间的间距,以产生最佳结果。

OP说(我引用)

请注意枚举如何包含食物的子类别以及子类别。 在我的真实场景中,我有未知数量的顶级类别和 未知数量的子级别类别(包括未知级别的 子类别)

那么您就没有枚举了:您有某种类型的层次结构。枚举(按设计)封装某种整型,并具有固定数量的元素。事实上,它们基本上是定点整数,这就为可用位数设置了上限:枚举的大小为8位、16位、32位或64位

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

请注意,为其类别查询
Foods
值需要进行一些微调,如下所示:

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

我不会在凌晨2:30冲出家门去买Ben&Jerry's。当你知道你可以拥有任意数量的元素时,尝试用Enum来做这件事有点疯狂。我们大多数人都使用一个元素树,这些元素之间具有层次关系,通常存储在关系数据库或XML或其他形式中
myclass.HasAncestorCategory(“Meat”)
更简单。仅供参考-我不想继承枚举类型。我正在尝试继承位值。在这种情况下,“继承”是一个误导性的术语,但它在某种程度上描述了我的意图。示例:按位值0x12“继承”0x2,即((0x2&0x12)=(0x2))的计算结果为true。
Foods item     = Foods.Hamburger ;
Foods category = (Foods) ( (ulong)item & (ulong)Foods.CategoryMask ) ;