打印标志枚举作为单独的标志
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了打印标志枚举作为单独的标志相关的知识,希望对你有一定的参考价值。
我有一个像这样定义的标志枚举:
[Flags]
public enum MyEnum
{
None = 0x00,
Choice1 = 0x01,
Choice2 = 0x02,
Choice3 = 0x04,
Default = Choice1 | Choice2,
All = Default | Choice3
}
我想要一种方法来打印MyEnum.Default
中包含哪些标志。在这种情况下,我希望输出类似于“Choice1,Choice2”。
简单地打印MyEnum.Default.ToString()
的问题是当我想要“Choice1,Choice2”时输出将是“默认”。
这是一个选项,但如果我使用它,我每次更改枚举时都必须更新打印。
((StudyData.Choice1 & StudyData.Default) == StudyData.Choice1 ? StudyData.Choice1.ToString() : "") + ", " +
((StudyData.Choice2 & StudyData.Default) == StudyData.Choice2 ? StudyData.Choice2.ToString() : "") + ", " +
((StudyData.Choice3 & StudyData.Default) == StudyData.Choice3 ? StudyData.Choice3.ToString() : "")
有没有人有更清洁的方式这样做?理想情况下,我想要一种打印MyEnum.Default
中包含的标志的方法,而不必在每次添加新标志或更改默认值时更改打印代码。
谢谢!
使用扩展方法我在相关问题上写了here,这应该很简单:
var value = MyEnum.Default;
var str = String.Join(", ", value.GetIndividualFlags());
// "Choice1, Choice2"
这是扩展方法:
static class EnumExtensions
{
public static IEnumerable<Enum> GetFlags(this Enum value)
{
return GetFlags(value, Enum.GetValues(value.GetType()).Cast<Enum>().ToArray());
}
public static IEnumerable<Enum> GetIndividualFlags(this Enum value)
{
return GetFlags(value, GetFlagValues(value.GetType()).ToArray());
}
private static IEnumerable<Enum> GetFlags(Enum value, Enum[] values)
{
ulong bits = Convert.ToUInt64(value);
List<Enum> results = new List<Enum>();
for (int i = values.Length - 1; i >= 0; i--)
{
ulong mask = Convert.ToUInt64(values[i]);
if (i == 0 && mask == 0L)
break;
if ((bits & mask) == mask)
{
results.Add(values[i]);
bits -= mask;
}
}
if (bits != 0L)
return Enumerable.Empty<Enum>();
if (Convert.ToUInt64(value) != 0L)
return results.Reverse<Enum>();
if (bits == Convert.ToUInt64(value) && values.Length > 0 && Convert.ToUInt64(values[0]) == 0L)
return values.Take(1);
return Enumerable.Empty<Enum>();
}
private static IEnumerable<Enum> GetFlagValues(Type enumType)
{
ulong flag = 0x1;
foreach (var value in Enum.GetValues(enumType).Cast<Enum>())
{
ulong bits = Convert.ToUInt64(value);
if (bits == 0L)
//yield return value;
continue; // skip the zero value
while (flag < bits) flag <<= 1;
if (flag == bits)
yield return value;
}
}
}
用[FlagsAttribute]
装饰你的枚举。它几乎完全符合您的要求:
[FlagsAttribute]
public enum FooNum
{
foo = 0,
bar = 1,
lulz = 2,
borkbork = 4
}
FooNum f = FooNum.bar | FooNum.borkbork;
Debug.WriteLine(f.ToString());
应该给你:
酒吧,borkbork
using System;
using System.Collections.Generic;
using System.Text;
namespace printStar
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter the value ");
int k = int.Parse(Console.ReadLine());
int n = k - 1;
int x = 2 * (k - 1) + 1;
for (int p = 0; p <= n; p++)
{
for (int j = k - 1; j >= 0; j--)
{
Console.Write(" ");
}
for (int i = 0; i <= (x - 2 * (k - 1)); i++)
{
if (i % 2 == 1)
{
Console.Write("*");
}
else
{
Console.Write(" ");
}
}
Console.WriteLine();
k--;
}
Console.ReadLine();
}
}
}
我用最短,最清晰的代码解决了这个问题,我期望它能很好地运行,尽管在几个地方都有拳击。以您的类型为例:
MyEnum e = MyEnum.Choice1 | MyEnum.Choice2;
string s = FlagsEnumToString<MyEnum>(e); // Returns "Choice1, Choice2"
这就是它的实现方式:
const string Separator = ", ";
public static string FlagsEnumToString<T>(Enum e)
{
var str = new StringBuilder();
foreach (object i in Enum.GetValues(typeof(T)))
{
if (IsExactlyOneBitSet((int) i) &&
e.HasFlag((Enum) i))
{
str.Append((T) i + Separator);
}
}
if (str.Length > 0)
{
str.Length -= Separator.Length;
}
return str.ToString();
}
static bool IsExactlyOneBitSet(int i)
{
return i != 0 && (i & (i - 1)) == 0;
}
可能会提出一些意见,我将首先解决这些问题:
我需要调用你的方法提供类型和变量?
因为这不能用通用的T
参数隐式地完成。 T
不能投射到Enum
与HasFlag
一起使用。不,也没有使用where T : struct, IConvertible
。
foreach
还使用object
?
是的,也是为了能够施展。只有qazxsw poi可以投射到其他类型qazxsw poi,qazxsw poi,object
。
我认为这可以通过使用临时变量在循环内部转换为
T
来优化。
我想是的,是的。为清楚起见,此代码是这样写的。所以,是的,如果你愿意,可以摆脱那些int
电话。
我认为你仍然可以使用
Enum
作为int
变量并节省施法。
不,因为你需要一个演员到HasFlag
而且只能从Enum
完成。可能有“更好”的解决方案,但这绝对是最短且最清晰的解决方案。
单个linq声明打印:
foreach
更新版本仅打印明确定义的值:
T
使用object
见var names = Enum.GetValues(typeof(MyEnum))
.Cast<MyEnum>()
.Where(a => (values & a) == a)
.Select(a => a.ToString())
.Aggregate((current, next) => current + ", " + next);
以上是关于打印标志枚举作为单独的标志的主要内容,如果未能解决你的问题,请参考以下文章
将标志添加到枚举后:Wcf 错误:错误 5 自定义工具错误:无法为服务引用“MyService”生成代码