支持继承的枚举位字段
我对这个问题的标题表示歉意,但我想不出更好的方法来描述我想要完成的任务。
我想使用 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个类别)
想要设置枚举的位值,以便子类别(和子类别)将“继承”其直接父级的位值。
我希望避免 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!");
这个问题让我困惑的是枚举中的每个食物项使用哪些位值。我最初是这样开始的:
[Flags]
enum Foods
{
// Top Level foods
Meat = 0x1,
Fruit = 0x2,
Vegetables = 0x4,
Dairy = 0x8,
Grain = 0x10,
BenJerrysOatmealCookieChunk = 0x20, // ;)
...and so on.
}
..但是因为我不知道会有多少级别(枚举列表会随着时间的推移而增长)..我不知道如何创建我的位值以便它们允许增长。
以前有人尝试过这样做吗?如果是这样,您的位值的业务逻辑是什么?
我有一种偷偷摸摸的感觉这个问题需要赏金;)
I apologize for the Title of this Question, but I couldn't think of a better way to describe what I'm trying to accomplish..
I want to make an Enum using the Flags attribute whereby the bitwise values of the enum create somewhat of an inheritance schema.
Example: Say we have a bit field enum of food:
[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,
}
Notice how the enum contains sub-categories of food as well as sub-sub-categories. In my real-world scenario, I have an unknown number of top-level categories and an unknown number of sub-level categories (including an unknown level of sub-sub-sub-n-categories)
I would like to set the bit values of the enum such that sub-categories (and sub-sub-n-categories) will "inherit" the bit value of its immediate parent.
I am wanting to avoid the client setter of the Foods property to have to explicitly set all flags for a particular food. In other words, I do not want the client setter to have to do something like:
myClass.Foods = Foods.Tritip | Foods.Beef | Foods.Meat;
I am trying to create a construct so that the client setter simply has to set one flag and all parents of that flag are implicit within the child flag.
So if the client setter did this:
myClass.Foods = Foods.Tritip;
We would be able to run the following conditions successfully:
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!");
What confuses me about this problem is what bit values to use for each food item in the enum. I initially started out with:
[Flags]
enum Foods
{
// Top Level foods
Meat = 0x1,
Fruit = 0x2,
Vegetables = 0x4,
Dairy = 0x8,
Grain = 0x10,
BenJerrysOatmealCookieChunk = 0x20, // ;)
...and so on.
}
.. but since I don't know how many levels there will be (the enum list will grow over time).. I don't know how to create my bit values so that they allow for growth.
Has anyone attempted to do this before? If so, what was your business logic for your bit values?
I have a sneaky feeling this Question will need a bounty ;)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以通过在枚举声明本身内部执行按位或来完成此操作。虽然这不会像通常使用 Flags 属性那样为您提供一个干净的 ToString,但它确实为您提供了所需的结果:
我使用 ulong 作为枚举的基础,以便您为子类别获得更多空间。我没有从尽可能最高的位开始,但如果我是你,我会这样,以便有空间来表示更深层次的类别。此外,您还需要调整子类别之间的间距以产生最佳结果。
You could do this by doing bitwise OR inside of the enum declaration itself. While this will not give you a nice clean ToString like you normally get with the Flags attribute, it does give you the desired result:
I used ulong for the enum's base so that you get more space for subcategories. I didn't start at the highest order bit possible, but if I were you, I would so that there would be room to represent deeper categories. Also, you'd want to play around with the spacing between sub-categories to yield the optimal results.
OP说(我引用)
那么你就没有枚举了:你有某种类型层次结构。枚举(根据设计)包装某种整数类型并具有固定数量的元素。它们本质上是定点整数,这一事实对可用位数设置了上限:枚举的大小为 8 位、16 位、32 位或 64 位。
考虑到这些限制枚举,您可以执行类似以下操作(并且您不需要或不需要
[Flags]
属性)。在下面的示例中,我为“类别”保留了 32 位,为“子类别”保留了 32 位。请注意,询问其类别的
Foods
值将需要一些调整,如下所示:OP said (and I quote)
Then you don't have an enum: you have some sort of type hierarchy. Enums (by design) wrap some sort of integral type and have a fixed number of elements. The fact that they are fundamentally fixed-point integers puts an upper bound on the number of available bits: an enum is 8-, 16-, 32- or 64-bits in size.
Given those restriction enums, you can do something like the following (and you don't need or want the
[Flags]
attribute). In the example below, I've reserved 32 bits for the "category" and 32 bits for the "subcategory".Note that interrogating a
Foods
value for its category will requires some bit twiddling, like so:这是不可能的。枚举不能从其他枚举继承。事实上,所有枚举实际上都必须继承自 System.Enum。 C# 允许语法更改枚举值的底层表示形式,这看起来像继承,但实际上它们仍然继承自 System.enum。
有关完整详细信息,请参阅 CLI 规范的第 8.5.2 节。规范中的相关信息
但是,您可以通过基类和派生类实现您想要的效果。
This is not possible. Enums cannot inherit from other enums. In fact all enums must actually inherit from System.Enum. C# allows syntax to change the underlying representation of the enum values which looks like inheritance, but in actuality they still inherit from System.enum.
See section 8.5.2 of the CLI spec for the full details. Relevant information from the spec
You could, however, achieve what you want with a base class and derived classes.