C# 从具有多个零值的枚举中获取项名称
我在处理一些具有多个零值的遗留枚举时遇到困难。每当我对其中一个非零值调用C# 从具有多个零值的枚举中获取项名称,c#,.net,string,enums,formatting,C#,.net,String,Enums,Formatting,我在处理一些具有多个零值的遗留枚举时遇到困难。每当我对其中一个非零值调用ToString,除第一个零值外,其他所有值都包括在内 是否有任何方法可以在不诉诸字符串操作或反射的情况下隔离非零值名称 //all of the following output "Nada, Zilch, One" Console.WriteLine(TestEnum.One); Console.WriteLine(Convert.ToString(TestEnum.One)); Console.WriteLine(Ty
ToString
,除第一个零值外,其他所有值都包括在内
是否有任何方法可以在不诉诸字符串操作或反射的情况下隔离非零值名称
//all of the following output "Nada, Zilch, One"
Console.WriteLine(TestEnum.One);
Console.WriteLine(Convert.ToString(TestEnum.One));
Console.WriteLine(TypeDescriptor.GetConverter(typeof(TestEnum))
.ConvertToString(TestEnum.One));
[Flags]
enum TestEnum
{
Zero = 0,
Nada = 0,
Zilch = 0,
One = 1
}
编辑
我理解,不建议使用具有相同值的多个项,但是所讨论的枚举是在旧程序集中定义的,我无法更改。事实上,mscorlib v4中有12个公共枚举违反了此建议,这是由以下简单LINQ查询确定的:
var types = typeof (void).Assembly.GetTypes()
.Where(type => type.IsEnum &&
type.IsPublic &&
Enum.GetValues(type).Cast<object>()
.GroupBy(value => value)
.Any(grp => grp.Count() > 1))
.ToList();
var types=typeof(void).Assembly.GetTypes()
.Where(type=>type.IsEnum&&
类型.IsPublic&&
Enum.GetValues(type).Cast()
.GroupBy(值=>value)
.Any(grp=>grp.Count()>1))
.ToList();
好的,首先。我听到他们用了一些更有力的词来表达他们在编译中没有强制执行的内容:
避免将标志枚举值设置为零,除非该值用于指示清除了所有标志。这样的值应该按照下一个指南中的描述进行适当命名。。。不要将标志枚举的零值命名为None。对于标志枚举,该值必须始终表示清除了所有标志
好的,那么为什么会发生这种情况呢?从我看来,它是Enum.ToString
行为异常:
如果多个枚举成员具有相同的基础值,并且您尝试根据其基础值检索枚举成员名称的字符串表示形式,则代码不应对方法将返回的名称进行任何假设
编辑:我可以复制您的结果,但是我找不到更多关于为什么它会开始打印其他0值的文档。我希望它不会打印它们
你能用鼠标右键单击->重构->重命名它们,然后删除其他的吗?这似乎更容易,而且与Microsoft的建议相比也更少。假设您有一个稍微复杂的枚举,例如:
[Flags]
public enum TestEnum
{
Zero = 0,
Nada = 0,
Zilch = 0,
One = 1,
Two = 2,
Four = 4,
}
[Flags]
public enum TestEnum
{
Zero = 0,
Nada = 0,
Zilch = 0,
One = 1,
Two = 2,
Three = 3,
Four = 4
}
您可以实现一个简单的方法,为您返回字符串值,如下所示:
public static string TestEnumToString(TestEnum value)
{
var result = new List();
if (value == TestEnum.Zero)
{
result.Add("Zero");
}
if (value == TestEnum.Nada)
{
result.Add("Nada");
}
if (value == TestEnum.Zilch)
{
result.Add("Zilch");
}
if ((value & TestEnum.One) != 0)
{
result.Add("One");
}
if ((value & TestEnum.Two) != 0)
{
result.Add("Two");
}
if ((value & TestEnum.Four) != 0)
{
result.Add("Four");
}
return string.Join(",", result);
}
这里有一个选择。它能用,但有点难看。变量的值/名称不会更改,因此只需计算一次
假设您的枚举稍微复杂一些,例如:
[Flags]
public enum TestEnum
{
Zero = 0,
Nada = 0,
Zilch = 0,
One = 1,
Two = 2,
Four = 4,
}
[Flags]
public enum TestEnum
{
Zero = 0,
Nada = 0,
Zilch = 0,
One = 1,
Two = 2,
Three = 3,
Four = 4
}
以下是一些您可以使用的代码:
var input = TestEnum.One | TestEnum.Two;
var values = (TestEnum[]) Enum.GetValues(typeof (TestEnum));
var names = Enum.GetNames(typeof (TestEnum));
var result = values
.Select((value, index) =>
input == value || (value != 0 && (input & value) == value)
? names[index]
: null)
.Where(name => name != null);
var text = string.Join(", ", result);
Console.WriteLine(text);
通常只有一个零值。事实上,通常的做法是不重复任何值。这是一个枚举,依赖于“backing”值存在固有的危险。您能展示一些代码如何使用这些标志吗?它们是否用作位掩码?因为这显然是不需要的行为,所以您可能需要对此提交错误报告:。这是在程序集中定义的旧枚举,我无法更改。您为什么反对反射?有什么特别的原因吗?这绝对是可行的。我并不完全反对,但我宁愿它只是作为最后的手段。另外,我的代码可能需要在部分信任环境中执行。请仅为代码设置代码格式。它使纯文本更难阅读。(虽然答案是正确的。)啊,是“>”。它看起来漂亮多了!这里的示例不太有效,因为它被标记为“flags”。如果我的值为0x03,但枚举中只有0x01和0x02,则会抛出AgumentException。此解决方案会给未来的开发人员带来维护负担。我更喜欢你的其他建议。我已经使你的LINQ代码更加地道,希望你不介意。我喜欢这个解决方案,但是它不适用于0值。