4

次の列挙型のセットがあります。

[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),
}

列挙型は、子列挙型がその親を意味する階層構造を表し、任意の数のフラグを適用できるという考え方です。

私が見ている問題は、デバッグ中にすべての子列挙型が名前または名前のセットとして表されていないことです。IE, Categories.F= "F" but Categories.F2= 16777248. 私はCategories.F2= "F, F2" または少なくとも "F2"を望んでいました

列挙型をフラグとして認識したままにするにはどうすればよいですか? 私がやろうとしていることを達成するためのより良い方法はありますか?

4

2 に答える 2

3

デバッガーの値が値と異なるのは非常に奇妙ToStringです。documentationによると、2つは一致するはずです(Enumタイプが実際にオーバーライドされるためToString)。

C# オブジェクトにオーバーライドがある場合ToString()、デバッガーはオーバーライドを呼び出し、標準の代わりにその結果を表示します{<typeName>}

明らかに、これは列挙型では機能しません。私の最善の推測は、デバッガーが特別な文書化されていない列挙型の処理を行おうとしているということです。を追加すると、DebuggerDisplayAttributeこの動作がオーバーライドされて問題が明らかに解決されます。

[DebuggerDisplay("{ToString()}")]
[Flags]
public enum Categories : uint
{
    ...
}

Categories.F2.ToString() = "F、F2"

F2C# は、列挙型に既に独自の名前を持っているため、その魔法を行いません。次のように、個々のメンバーを手動でマークできます。

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);
}

残念ながら、拡張メソッドは では使用できませんが、YMMVDebuggerDisplayAttributeを使用できますが、これを試すことができます。DebuggerTypeAttribute

[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);
    }
}
于 2013-04-06T06:31:09.573 に答える
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;
}
于 2013-04-06T06:46:53.233 に答える