我有以下一组枚举:
[Flags]
public enum Categories : uint
{
A = (1 << 0),
B = (1 << 1),
B1 = B | (1 << 16),
B2 = B | (1 << 17),
B3 = B | (1 << 18),
B4 = B | (1 << 19),
B5 = B | (1 << 20),
C = (1 << 2),
C1 = C | (1 << 21),
D = (1 << 3),
D1 = D | (1 << 22),
D2 = D | (1 << 23),
E = (1 << 4),
F = (1 << 5),
F1 = F | (1 << 23),
F2 = F | (1 << 24),
F3 = F | (1 << 25),
F4 = F | (1 << 26),
F5 = F | (1 << 27),
G = (1 << 6),
H = (1 << 7),
H1 = H | (1 << 28),
}
这个想法是枚举表示一个层次结构,其中子枚举意味着它的父节点,并且可以应用任意数量的标志。
我看到的问题是在调试期间没有将所有子枚举表示为名称或名称集。 I.E.,Categories.F
=“F”但Categories.F2
= 16777248.我希望Categories.F2
=“F,F2”或至少“F2”
如何让我的枚举仍被识别为旗帜?有没有更好的方法来完成我想要做的事情?
答案 0 :(得分:2)
调试器中的值与ToString
值不同,这很奇怪。根据{{3}},两者应该匹配(因为Enum
类型确实覆盖了ToString
)。
如果C#对象有一个被覆盖的
ToString()
,调试器将调用覆盖并显示其结果而不是标准{<typeName>}
。
显然这不适用于枚举。我最好的猜测是调试器正在尝试对枚举类型进行一些特殊的,未记录的处理。添加documentation显然可以通过覆盖此行为来解决问题。
[DebuggerDisplay("{ToString()}")]
[Flags]
public enum Categories : uint
{
...
}
Categories.F2.ToString()=“F,F2”
C#不会为你做那个魔术,因为F2
已经在枚举中拥有了它自己的名字。您可以手动标记各个成员,如下所示:
public enum Categories
{
[Description("F, F2")]
F2 = F | (1 << 24),
}
然后编写代码以转换为描述。
public static string ToDescription(this Categories c)
{
var field = typeof(Categories).GetField(c.ToString());
if (field != null)
{
return field.GetCustomAttributes().Cast<DescriptionAttribute>().First().Description;
}
}
...
Categories.F2.ToDescription() == "F, F2";
或者你可以自己做一些魔术:
public static string ToDescription(this Categories c)
{
var categoryNames =
from v in Enum.GetValues(typeof(Categories)).Cast<Category>()
where v & c == c
orderby v
select v.ToString();
return String.Join(", ", categoryNames);
}
不幸的是,扩展方法无法与DebuggerDisplayAttribute
一起使用,但您可以使用DebuggerDisplayAttribute
,YMMV,但您可以尝试这样做:
[DebuggerType("CategoryDebugView")]
[Flags]
public enum Categories : uint
{
...
}
internal class CategoryDebugView
{
private Category value;
public CategoryDebugView(Category value)
{
this.value = value;
}
public override string ToString()
{
var categoryNames =
from v in Enum.GetValues(typeof(Categories)).Cast<Category>()
where v & c == c
orderby v
select v.ToString();
return String.Join(", ", categoryNames);
}
}
答案 1 :(得分:1)
你可以通过一点点工作来完成你的要求。我在Categories
上创建了一些扩展方法,它们使用HasFlag()
来确定枚举值是否具有特定父级,然后对它们调用ToString()
并连接结果。
public static class CategoriesExtensionMethods
{
public static Categories GetParentCategory(this Categories category)
{
Categories[] parents =
{
Categories.A,
Categories.B,
Categories.C,
Categories.D,
Categories.E,
Categories.F,
Categories.G,
Categories.H,
};
Categories? parent = parents.SingleOrDefault(e => category.HasFlag(e));
if (parent != null)
return (Categories)parent;
return Categories.None;
}
public static string ToStringWithParent(this Categories category)
{
var parent = GetParentCategory(category);
if (parent == Categories.None)
return category.ToString();
return string.Format("{0} | {1}", parent.ToString(), category.ToString());
}
}
然后我们可以像这样使用它:
var f1 = Categories.F1;
var f1ParentString = f1.ToStringWithParent();
// f1ParentString = "F | F1"
var f = Categories.F;
var fParentString = f.GetParentCategory();
// fParentString = "F"
如果您不想指定所有父母,这是实施GetParentCategory()
的更好的方式。
public static Categories GetParentCategory(this Categories category)
{
var values = Enum.GetValues(typeof(Categories)).Cast<Categories>();
var parent = values.SingleOrDefault(e => category.HasFlag(e) && e != Categories.None && category != e);
if (parent != Categories.None)
return (Categories)parent;
return Categories.None;
}