【问题标题】:Can Enum.ToString support precision specifiers like "X2"?Enum.ToString 可以支持像“X2”这样的精度说明符吗?
【发布时间】:2017-03-29 18:36:20
【问题描述】:

Enum.ToString(string) 不支持直接使用精度说明符,例如 X2D5 来对数值应用填充。 Formattings like ToString("X") or ToString("D") are implemented and well documented。当然,我可以在之前明确地将其转换为int,因此可以利用为整数实现的格式说明符将其转换为填充字符串。

我想知道是否有一些直接支持枚举的这种功能而无需强制转换它们。乍一看,这似乎很奇怪,因为它不像整数或其他数字类型那样直接实现。但也许我遗漏了一些更重要的东西,可以明确地解释它不是针对枚举做的?

public enum Number
{
    Ten = 10
}

Console.WriteLine(Number.Ten);                      //OK: Ten
Console.WriteLine(Number.Ten.ToString());           //OK: Ten
Console.WriteLine(Number.Ten.ToString("D"));        //OK: 10
Console.WriteLine(Number.Ten.ToString("D5"));       //Expected 00010 - Failed: System.FormatException, can only be "G","g","X","x","F","f","D" or 
Console.WriteLine(Number.Ten.ToString("X"));        //OK: 0000000A
Console.WriteLine(Number.Ten.ToString("X2"));       //Expected 0A - Failed: System.FormatException, can only be "G","g","X","x","F","f","D" or "d"
Console.WriteLine(10.ToString("X2"));               //OK: 0A
Console.WriteLine(10.ToString("D5"));               //OK: 00010
Console.WriteLine(((int)Number.Ten).ToString("X2"));//OK: 0A 

来自accepted answer 的简短摘要: 它没有明确地存在,因为它已经根据底层类型的大小隐含地完成了。因此,如果您喜欢 X2 而不是 X8,只需使用 byte 作为基础类型,ToString("X") 的行为将类似于 ToString("X2")

【问题讨论】:

  • 这就是生活。如果您需要为特定枚举编写扩展方法,请考虑编写此方法。
  • 我不确定您期望得到什么答案。只有语言设计者才能告诉你原因。可能是因为想要或需要做这件事有点奇怪。解决方案就是强制转换:((int)Number.Ten).ToString("D5")
  • 就我个人而言,我很惊讶他们支持任何格式。这似乎是一个非常极端的案例。
  • 与-1相反,我认为这是一个很好的问题,我希望我能得到答案。希望我的 +1 有所帮助。
  • @Marwie:因为它不是整数,它是一个枚举。这不是枚举的用途。

标签: c# enums tostring


【解决方案1】:

也许因为枚举可以是字节、sbyte、short、ushort、int、uint、long 或 ulong。

如果你查看 .net 源代码,你会看到 ToString("X") 的实现:

switch (Convert.GetTypeCode(value))
  {
    case TypeCode.Boolean:
      return Convert.ToByte((bool) value).ToString("X2", (IFormatProvider) null);
    case TypeCode.Char:
      return ((ushort) (char) value).ToString("X4", (IFormatProvider) null);
    case TypeCode.SByte:
      return ((byte) (sbyte) value).ToString("X2", (IFormatProvider) null);
    case TypeCode.Byte:
      return ((byte) value).ToString("X2", (IFormatProvider) null);
    case TypeCode.Int16:
      return ((ushort) (short) value).ToString("X4", (IFormatProvider) null);
    case TypeCode.UInt16:
      return ((ushort) value).ToString("X4", (IFormatProvider) null);
    case TypeCode.Int32:
      return ((uint) (int) value).ToString("X8", (IFormatProvider) null);
    case TypeCode.UInt32:
      return ((uint) value).ToString("X8", (IFormatProvider) null);
    case TypeCode.Int64:
      return ((ulong) (long) value).ToString("X16", (IFormatProvider) null);
    case TypeCode.UInt64:
      return ((ulong) value).ToString("X16", (IFormatProvider) null);
    default:
      throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
  }

如果您将代码更改为此,它将使用 ToString("X2"):

public enum Number : byte
{
    Ten = 10
}

【讨论】:

  • 感谢从 .NET 中提取这个有趣的代码。所以实际上底层类型实际上已经暗示了 X2/X4 等格式......
  • 我接受这个作为答案,因为似乎这个问题很快就会结束,这个答案正朝着正确的方向发展:即底层类型在使用 ToString("X") 时已经暗示了格式精度.
【解决方案2】:

Enum.ToString() 的实现表明它被设计成只能使用某些格式说明符:

    public String ToString(String format) {
        if (format == null || format.Length == 0)
            format = "G";

        if (String.Compare(format, "G", StringComparison.OrdinalIgnoreCase) == 0)
            return ToString();

        if (String.Compare(format, "D", StringComparison.OrdinalIgnoreCase) == 0)
            return GetValue().ToString();

        if (String.Compare(format, "X", StringComparison.OrdinalIgnoreCase) == 0)
            return InternalFormattedHexString(GetValue());

        if (String.Compare(format, "F", StringComparison.OrdinalIgnoreCase) == 0)
            return InternalFlagsFormat((RuntimeType)GetType(), GetValue());

        throw new FormatException(Environment.GetResourceString("Format_InvalidEnumFormatSpecification"));
    }

我认为它涵盖了最常见的场景:能够显示其数字、十六进制或字符串表示形式。显式转换的解决方法似乎足够便宜,不需要将其烘焙到框架中。

如果您想在不知道具体类型是什么的情况下使用基础类型的 ToString()(无需强制转换!),您可以执行以下操作:

var formattedValue = string.Format("{0:X2}", 
    Convert.ChangeType(Number.Ten, Number.Ten.GetTypeCode()));

这将输出“0A”。这可以很容易地包含在扩展方法中。

【讨论】:

猜你喜欢
  • 2013-05-26
  • 2012-02-27
  • 2015-11-07
  • 2011-11-26
  • 2012-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多