Enum.Parse方法返回一个不同于作为参数传入的枚举成员的枚举成员

时间:2013-12-04 23:37:42

标签: c# enums

我希望以下调用Parse方法返回枚举成员EN_CA,但它会返回EN。

Enum.Parse(LanguageType, "EN_CA", true);

其中:

enum LanguageType
{
  EN = 0,
  EN_CA = 0,
  FR = 1
}

似乎Parse方法只是抓取第一个映射到传递给它的参数值的成员.Parse方法在从字符串转换为枚举成员的过程中似乎丢失了信息。更改EN_CA和EN的顺序会使上述调用返回EN_CA,但这不会解决问题,因为在调用“EN”方法时会导致类似的问题。

其他与上下文相关的信息:在我的代码中,LanguageType Enum表示字典的索引,这些索引用于本地化语言。

有没有人知道如何将两个枚举成员映射到相同的值,同时能够从Enum.Parse获得适当的成员?我是否只需要实现我自己的Enum.Parse版本,它不会将具有相同值的成员合并为一个?

6 个答案:

答案 0 :(得分:3)

枚举成员与其他枚举成员不同,如果,如果它具有不同的值。有效地,枚举的成员被命名为常量,除了它们持有的值之外,它们之间没有真正的区别。

LanguageType枚举中,您有两个相同值的标签,无法区分它们。试试这个:

Console.WriteLine("{0} == {1} ? {2}", 
    LanguageType.EN.ToString(), 
    LanguageType.EN_CA.ToString(),
    LanguageType.EN == LanguageType.EN_CA);

输出结果为:

EN == EN ? True

LanguageType.EN_CA分配给变量时会发生同样的事情,然后稍后检查变量以查看它包含的内容。你得到的是LanguageType.EN

这里的关键是成员的在大多数情况下都是非常重要的,其中成员的位置是冲突期间的决胜局。当两个成员具有相同的值时,首先声明的成员是您在进行字符串转换时将看到的成员,包括在IDE中检查值时。

因此,实际上您的值LanguageType.EN_CA只是值LanguageType.EN的别名。

虽然我可以想到几个可爱的用途 - 比如解析具有相同值的多个表示的传入数据 - 在大多数现实世界中做这件事真的很可怕环境,尤其是,如果您希望能够进行完全对称的序列化/反序列化。

现在,关于您的本地化Dictionary ...

在Dictionary中多次存储相同的类对象的成本非常低,因为类对象是通过引用存储的。假设您有一个Localization类,以下代码在存储方面效率不是特别低:

enum LanguageType
{
    EN, EN_CA, EN_US, EN_GB, EN_AU, FR
}


Dictionary<LanguageType, Localization> localizations = new Dictionary<LanguageType, Localization>();

localizations[LanguageType.EN] = new Localization("EN");
localizations[LanguageType.EN_CA] = localizations[LanguageType.EN];
localizations[LanguageType.EN_US] = localizations[LanguageType.EN];
localizations[LanguageType.EN_GB] = localizations[LanguageType.EN];
localizations[LanguageType.EN_AU] = localizations[LanguageType.EN];

即使Localization对象包含大量资源,上面的代码也只创建了一个实例。您为LanguageType成员获得了不同的值,而Dictionary为您做了映射。

答案 1 :(得分:2)

您在枚举中定义了0两次 - 这不起作用。每个值必须是唯一的,或者枚举如何识别其值 - 它实际上存储为整数。

将其更改为:

enum LanguageType
{
  EN = 0,
  EN_CA = 1,
  FR = 2
}

修改

正如Greenish所指出的,您可以为同一个值定义多个名称,作为一种别名。使用两个或多个名称将返回相同的值。如果您尝试从整数值获取字符串值,您将获得为该整数定义的第一个值。

在您的情况下,您无法使用枚举实现所需。你应该建立自己的自定义类来实现它。

答案 2 :(得分:1)

枚举基本上都是整数。并且可以为单个数字指定不同的名称(如示例中的0)。

Enum.Parse搜索第一个正确的实例 - 此处您的有效名称为0 == 0。所以解决方案是改变你的数字(甚至只是删除它们,因为它们是0,1,2)

enum LanguageType
{
  EN,
  EN_CA,
  FR
}

答案 3 :(得分:1)

我想到了一种方式,但它是凌乱的脆弱和naff。它再次说明了你为自己挖的洞......

int index = Enum.GetNames(typeof(LanguageType)).indexof("EN_CA")

会给你1个

然后像

switch(index)
{
  case 0 : return LanguageType.EN;
  case 1 : return LangaugeType.EN_CA;
  case 2 : return LanguageType.FR;
  default : // throw some useful exception maybe
   break
}

将返回您想要的成员。

可怕的不是吗?

Enum.GetValues(typeof(LanguageType))将返回[0,0,1]并且使用indexof 0当然是0,这就是Parse为您提供结果的原因。

答案 4 :(得分:0)

=0指定基础类型(int)中枚举值的表示。您已经为ENEN_CA提供了相同的表示形式,即0,因此现在它们实际上已成为相同值的两个标签。

Enum.Parse返回此值,它将等于两个标签。

潜在的问题是,您正在尝试将分层概念编码为扁平枚举。出于某些目的,所有英语国家的文化应该被平等对待,出于其他目的,你想区分它们。

我认为,解决方案是使用already present mechanisms for localizing your application,特别是CultureInfo应该替换您的枚举和Resources查找字典。


我有点惊讶,允许使用枚举:) 但MSDN documentation明确指出它是有效的,并举例说明它是如何有用的:

enum Color 
{
   Red,
   Green,
   Blue,
   Max = Blue
}

答案 5 :(得分:0)

所以这就是我解决问题的方法:

我无法通过让Enum.Parse方法返回我期望的内容来找到问题的清晰修复。(请参阅注释*)

我的解决方法是在生成的字典上应用GroupBy(LanguageIndex),该字典的索引重复,因此抛出异常。因为我希望EN_CA和EN在枚举中具有相同的值,而不会抛出异常而给出了我想要的内容。

我可以看到我的修复不是我最初提出的问题的实际答案,而忽略了背景;虽然我可能仍然适用于具有类似问题的其他环境。

注意* :我本来可以实现我自己的Enum.Parse版本 - 请参阅 this 以获得替代实施的答案 - 但这需要我把臭硬编码的东西放进我的代码中,所以我放弃了修复Parse方法。