我在代码中定义了多个标记枚举,类似于以下
[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);
}
答案 0 :(得分: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;
}
它基本上列出了set标志的值,除了那些“包含”其他标志的值。它通过获取正在测试的值,将其递减为零并检查原始值是否将该递减值设置为标志来计算出来。最后,除非没有设置标志,否则它将删除“None
”值。
像这样使用它:
Colors c = Colors.Purple;
Console.WriteLine(c.AsString());
答案 1 :(得分:0)
您可以使用HasFlag
method:
.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);
答案 2 :(得分: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
答案 3 :(得分:0)
4行代码中没有计算方法签名的答案。
0..RAND_MAX