具有重复值的枚举的 GetName
本文关键字:枚举 GetName | 更新日期: 2023-09-27 18:28:04
如果我在 C# 枚举中有重复的值,说
enum MyE {
value1 = 1,
value2 = 2,
valued = 1
}
以下字符串的值应该是什么?
MyE N = (MyE)1;
string V1 = N.ToString();
string V2 = GetName(MyE, 1);
V1 和 V2 必须包含相同的值,这是真的吗?这些值应该是什么?
我在 MSDN 或这里没有找到任何关于重复枚举的"取消引用"的任何内容,如果我错过了,请指出我一个链接。
实验表明:
V1 = "值 1">
和
V2 = "值 1">
但是,这并不能保证。Enum.GetName
上的 MSDN 页面指出:
如果多个枚举成员具有相同的基础值,则 GetName 方法保证它将返回其中一个枚举成员的名称。但是,它不保证它将始终返回同一枚举成员的名称。因此,当多个枚举成员具有相同的值时,应用程序代码不应依赖于返回特定成员名称的方法。
从Enum.GetName
方法文档(http://msdn.microsoft.com/en-us/library/system.enum.getname.aspx(的"备注"部分,它说:
如果多个枚举成员具有相同的基础值,则 GetName 方法保证它将返回其中一个枚举成员的名称。但是,它不保证它将始终返回同一枚举成员的名称。因此,当多个枚举成员具有相同的值时,应用程序代码不应依赖于返回特定成员名称的方法。
我运行了一个测试以查看实验中会发生什么,它总是返回定义的第一个值(在您的示例中为 value1(,但根据上面的官方文档,您不能依赖它(请参阅 @gluk47 的评论,表明野外的不同行为(。
我不同意其他答案陈述
。这不能保证...
。你不能依赖那个...
以及 MSDN 声明:
。您的应用程序代码永远不应该依赖于返回特定成员名称的方法...
故事
我的软件中有一个枚举
enum Blabla { A = 0, B = 1, C = 2, D = 3 }
在某些时候,A
值更改为AA
,后来AA
更改为AAA
。为了保持向后兼容性,我必须这样做
enum Blabla { A = 0, AA = 0, AAA = 0, B = 1, C = 2, D = 3 }
这允许将旧的枚举值(由旧版本的软件制作(反序列化为AAA
。
然后有一个打印Blabla
设置值的报告。在某些时候,每个使用新版本的客户都开始告诉我他们看到的价值AA
而不是AAA
。他们都看到了AA
(没有人报告看到A
(。
我做了什么?我只是更改顺序(直到结果AAA
(
enum Blabla { AAA = 0, A = 0, AA = 0, ...}
并进行了测试以确保将输出Blabla.AAA
作为AAA
。问题解决了?
证明
查看Enum.ToString()
(或Enum.GetName()
(的来源,它使用GetEnumName((,它调用Array.BinarySearch()
值的排序数组来查找值的索引。
二叉搜索的结果是确定性的:为其提供相同的参数将返回相同的结果。
所以:
- 如果不更改枚举,则结果将相同。
- 可以通过实验找到结果(或者通过了解二叉搜索的工作原理以及如何处理枚举(。
- 没有简单的规则来确定结果(例如,你不能说"它总是返回第一个定义的值"(。
enum
格式不太可能被更改(例如,定义顺序和值列表顺序不同(或Enum.ToString()
更改,但是可能会发生这种情况,因此请确保您对依赖返回值的情况进行了测试。
好吧,因为没有关于顺序的保证,过时的属性似乎对Enum
方法没有影响,我通常建议使用字符串属性进行序列化,并使用自定义代码来处理过时的值。
这样,主Enum
没有重复项,仅包含当前值。
根据序列化框架,您可能能够将字符串属性标记为可序列化但已过时,并将代码中使用的实际属性标记为序列化忽略。
若要处理字符串属性 setter 中的过时值,可以使用 [Obsolete] enum
或 switch 语句。通常,如果我有很多过时的值要处理,我可能会使用前者,如果我只有几个值要处理,我可能会使用后者。
此外,将代码放在帮助程序类或扩展方法中可能是有意义的,特别是当您从一堆位置加载或存储该值时。
虽然我没有在生产代码中尝试太多,但我想知道使用 struct
而不是 enum
来获得更多控制是否更好......但我认为它需要很多不容易通用的样板代码。
虽然这对派对来说可能有点晚,但这可能不是最好的主意,但是,我确实发现在我的情况下我不得不使用重复枚举的一个解决方法是使用这里问题的以下内容;从 C# 中的枚举获取字符串名称
var name = nameof(DeclaredEnum.EnumName);
结果是:
EnumName
您可以在此处阅读更多有关其实际工作原理的信息。