【问题标题】:Properly identifying enums with same underlying value正确识别具有相同基础价值的枚举
【发布时间】:2017-08-30 21:29:40
【问题描述】:

假设我定义了这个enum,其中几个成员具有相同的基础值:

enum Number
{
  One = 1,
  Eins = 1,
  Uno = 1
}

根据MSDN documentation

如果多个枚举成员具有相同的基础值,并且您尝试根据其基础值检索枚举成员名称的字符串表示形式,则您的代码不应对该方法将返回哪个名称做出任何假设。

例如,

var number = Number.One;
Console.WriteLine(number);

给我以下输出:

恩斯

打印所有枚举成员,

Console.WriteLine($"{Number.One} {Number.Eins} {Number.Uno}");

产生以下输出:

恩恩恩恩斯恩恩斯

但是,取每个成员的nameof

Console.WriteLine($"{nameof(Number.One)} {nameof(Number.Eins)} {nameof(Number.Uno)}");

给出以下结果:

一个Eins Uno

显然enum 成员可分离的。我可以利用这种分离,即有没有任何方法我可以将特定的Number 成员分配给变量,并且只要变量是访问了吗?

【问题讨论】:

  • 一开始你为什么会出现这种情况?
  • 看起来是摆脱枚举并使用全球化/资源文件的好地方。
  • 好吧,也许我不应该在示例中使用不同的语言。我的问题与国际化无关。
  • 如果您将变量转换为基础类型 (int),您将无法做到,否则,您可以查看 Enum.GetNames(Type) 函数
  • @AndersGustafsson - 当您被遗留代码困扰时,选项有时会受到限制,除非您有资源来重构和正确实现某些东西(通常情况并非如此)。

标签: c# enums


【解决方案1】:

我写了一些应该让它工作的东西

public static class NumberExtension
{
    private static Dictionary<int, string> pointers = new Dictionary<int, string>();
    public static unsafe void SetValue(this Number source, string value)
    {
        if (pointers.ContainsKey((int)&source))
            pointers[(int)&source] = value;
        else
            pointers.Add((int)&source, value);
    }
    public static unsafe string GetValue(this Number source)
    {
        if (pointers.ContainsKey((int)&source))
            return pointers[(int)&source];
        return source.ToString();
    }
}

并使用:

    Number num = default(Number);
    num.SetValue(nameof(Number.Uno));
    Console.WriteLine(num.GetValue());

但是,它看起来像是一种“黑客”,我不推荐它。如果您寻找更好的解决方案会更好。

【讨论】:

  • 谢谢,艾莉。不过,正如您自己所说,这对于我的需求来说太过“黑客”了,所以我宁愿考虑重构。
【解决方案2】:

我看到始终返回预期枚举名称的唯一可能性是在您的第一个基础类型旁边创建第二个 enum 并具有相同的值,但将成员限制为您期望的成员(和确保没有共享值)。然后,您可以从一个转换到另一个,并在依赖特定/预期成员的重构代码中使用新枚举。

一些方法

Console.WriteLine("{0:G}", (KnownNumber)Number.Eins); // > One
Console.WriteLine("{0:G}", (KnownNumber)Number.Uno); // > One
Console.WriteLine("{0:G}", (KnownNumber)Number.One); // > One

枚举.cs

public enum Number
{
  One = 1,
  Eins = 1,
  Uno = 1
}

public enum KnownNumber
{
  One = 1,
  Two = 2,
  Three = 3
}

Fiddle

【讨论】:

    【解决方案3】:

    显然enum 成员可分离的

    嗯,这并不完全正确......它们只能在编译时分离。

    你看,nameof 实际上是一个在编译时求值的表达式。它是一个常量表达式。这可以通过将nameof 表达式分配给const 来证明:

    const string a = nameof(Number.One);
    

    它编译。

    另一方面,尝试使用字符串插值来获取枚举值的字符串表示是在运行时评估的,因此无法编译:

    const string a = $"{Number.One}";
    

    在运行时,枚举案例是不可分离的,所以答案是:

    有什么方法可以将特定的 Number 成员分配给变量,并在访问变量时始终返回相同的成员?

    是“不”。

    【讨论】:

    • 我会让你再悬念一段时间,以防其他人也想回答:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-15
    • 2014-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多