1

次のようなコードで定義された複数のフラグ列挙型があります

[Flags]
public enum Colors
{
   None = 0,
   Red = 1,
   Green = 2,
   Blue = 4, 
   Purple = Red | Blue,
   Brown = Red | Green,
}

次のコードは、次の出力を生成します

Colors color1 = Colors.Red | Colors.Blue;
Colors color2 = Colors.Purple;
string s1 = color1.ToString(); // Sets s1 to "Purple"
string s2 = color2.ToString(); // Sets s2 to "Purple"



一致する組み合わせが定義されている場合でも、ビットごとの列挙型の個々のビットを出力するメソッドが必要です。

private void Foo()
{
  Colors color1 = Colors.Red | Colors.Blue;
  Colors color2 = Colors.Purple;
  string s1 = CreateColumnString(color1); // Sets s1 to "Red|Blue"
  string s2 = CreateColumnString(color2); // Sets s2 to "Red|Blue"
}

列挙型のすべての値をループして、値が 2 のべき乗であるかどうかを確認できると思いました。しかし、Enum 引数の基になる値を取得する方法がわかりません。

private string CreateColumnString(object value)
{
 //is this an enum with Flags attribute?
 if (value is Enum  && value.GetType().GetCustomAttributes(typeof(FlagsAttribute), true).Length > 0)
 {
    Enum e = (Enum)value;
    //Get a list of Enum values set in this flags enum
    IEnumerable<Enum> setValues = 
      Enum.GetValues(value.GetType())
          .Cast<Enum>()
          .Where(eachEnum => IsPowerOfTwo(eachEnum) && value.HasFlag(eachEnum)); 

    return string.Join("|", setValues);
 }
 else
 {
    return value != null ? value.ToString() : string.Empty;
 }
 return str;
}

private static bool IsPowerOfTwo(Enum e)
{
   int x = (int)e; //ERROR cannot convert type 'System.Enum' to 'ulong'
   return (x != 0) && ((x & (x - 1)) == 0);
}
4

4 に答える 4

1

これを行うためのより良い方法があるかもしれませんが、これはあなたが探していることをするはずです:

private static string AsString<T>(this T values)
{
    Enum v = (Enum)Convert.ChangeType(values, typeof(Enum));
    Array array = Enum.GetValues(typeof(T));
    IEnumerable<Enum> setFlags = array
        .Cast<Enum>()
        .Where(c => v.HasFlag(c) && IsDistinctValue(c));

    return values.Equals(default(T))
        ? default(T).ToString()
        : string.Join("|", setFlags.Where(c => Convert.ToInt32(c) != 0).Select(c => c.ToString()));
}

private static bool IsDistinctValue(Enum value)
{
    int current = Convert.ToInt32(value) >> 1;
    while (current > 0)
    {
        if ((Convert.ToInt32(value) & current) != 0)
        {
            return false;
        }
        current >>= 1;
    }

    return true;
}

基本的に、他のフラグを「含む」ものを除いて、設定されたフラグの値をリストします。テストされている値を取得し、それをゼロに向かって減分し、元の値にその減分された値がフラグとして設定されているかどうかを確認することで、これを把握します。最後に、Noneフラグが設定されていない限り、" " 値を削除します。

次のように使用します。

Colors c = Colors.Purple;
Console.WriteLine(c.AsString());
于 2012-12-11T23:05:06.757 に答える
0

HasFlagメソッドを使用できます:

.Where(e.HasFlag)

ただし、あなたのEnum.GetValues呼び出しは、列挙型が名前を付けたマルチビット値も取得すると思います。

編集:

作業に取り掛かる別のアプローチを次に示します。

if (Enum.GetUnderlyingType(e.GetType()) != typeof(int))
  throw new NotImplementedException();

var list = new List<Enum>();
for (int i = 1; i != 0; i <<= 1)
{
  var eachEnum = (Enum)(Enum.ToObject(e.GetType(), i));
  if (e.HasFlag(eachEnum))
    list.Add(eachEnum);
}

return string.Join(" | ", list);
于 2012-12-11T22:37:48.267 に答える
0

ここに別のアプローチがあります。選択肢が多ければ多いほど良いと思います:)

public static class EnumHelpers
{
    public static string ToStringExtended<T>(this Enum e)
    {
        if (!(e.GetType().GetCustomAttributes(typeof(FlagsAttribute), true).Length > 0))
            return e.ToString();

        List<string> eNames = new List<string>();
        foreach (T fish in Enum.GetValues(typeof(T)))
        {
            Enum num = fish as Enum;
            if (e.HasFlag(num) && Convert.ToInt32(fish) != 0 && Convert.ToInt32(fish) != Convert.ToInt32(e))
                eNames.Add(fish.ToString());
        }

        return eNames.Count > 1 ? String.Join("|", eNames.ToArray()) : e.ToString();
    }
}

使用法は、Fredirk が提案したものとほぼ同じです。

Colors c = Colors.Purple;
Console.WriteLine(c.ToStringExtended<Colors>());
// Output : Red|Blue
于 2012-12-11T23:54:08.777 に答える