【问题标题】:Why doesn't object have an overload that accepts IFormatProvider?为什么对象没有接受 IFormatProvider 的重载?
【发布时间】:2011-11-23 04:37:48
【问题描述】:

例如,当将decimal 转换为string 时,您使用CultureInfo.InvariantCulture 并将其作为IFormatProvider 传递。但是为什么这个重载不在object 中呢?

一个不错的实现是:

public virtual string ToString()
{
   // yadayada, usual ToString
}

public virtual string ToString(IFormatProvider provider)
{
   return ToString();
}

这不会对object 类造成任何伤害或好处,但是从它派生的对象可以替代重载,并且当您不确定类型时调用它会容易得多。

让我遇到这种情况的问题是,当我创建一个获取类的所有属性并将其写入 xml 的方法时。因为我不想检查对象的类型,所以我只打电话给ToString。但这是否是小数,输出将基于线程的CurrentCulture,这不是最佳的。我能看到的唯一解决方法是将CurrentCulture 更改为InvariantCulture,然后将其更改回原来的样子。但这会很丑陋,因为我必须编写 try finally 块等。

我当前的代码是:

        foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance).
            Where(c => ValidTypes.Contains(c.PropertyType)))
        {
            var value = property.GetValue(order, null);
            if (value != null)
            {
                writer.WriteElementString(property.Name, 
                value.ToString());
            }
        }

但我希望它是:

        foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance).
            Where(c => ValidTypes.Contains(c.PropertyType)))
        {
            var value = property.GetValue(order, null);
            if (value != null)
            {
                writer.WriteElementString(property.Name, 
                value.ToString(CultureInfo.InvariantCulture));
            }
        }

object 上没有这种重载有什么好处?

【问题讨论】:

    标签: c# .net object globalization


    【解决方案1】:

    尝试将您的value 转换为IFormattable

    foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance).
           Where(c => ValidTypes.Contains(c.PropertyType)))
    {
        var value = property.GetValue(order, null);
        if (value != null)
        {
            var formattable = value as IFormattable;
            writer.WriteElementString(property.Name, 
            formattable == null ? value.ToString() : formattable.ToString(null, CultureInfo.InvariantCulture));
        }
    }
    

    【讨论】:

    • IConvertible 实际上更有意义(除非您打算格式化数字。)
    • @dlev:我不同意 - OP 特别希望 just 进行格式化。鉴于类型可以轻松实现 IFormattable 但不是 IConvertible,并且 IFormattable 中的单个方法正是 OP 想要调用的方法,我认为 IFormattable 更有意义。
    • @Jon 根据 OP 的问题,他似乎有实际使用ToString()IConvertible 版本的经验,这就是我提到它的原因。不过,你的观点很好。
    【解决方案2】:

    Peter 解决方案的便捷扩展方法(已修改以测试 IConvertible)。

    public static string ToInvariantString(this object obj)
    {
        return obj is IConvertible ? ((IConvertible)obj).ToString(CultureInfo.InvariantCulture)
            : obj is IFormattable ? ((IFormattable)obj).ToString(null, CultureInfo.InvariantCulture)
            : obj.ToString();
    }
    

    【讨论】:

      【解决方案3】:

      尝试以下方法之一:

      string valueString = XmlConvert.ToString(value);
      string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
      

      XmlConvert.ToString() 是为 XML 设计的,因此它会更接近 XML 规范,例如使用“true”而不是“True”。但是,它也比 Convert.ToString() 更脆弱。例如,这会因为 UTC 时间而引发异常:

      XmlConvert.ToString(DateTime.UtcNow)
      

      但这有效:

      XmlConvert.ToString(DateTime.UtcNow, "o")
      

      【讨论】:

      • Convert.ToString 实际上强制转换为 IConvertible 和 IFormattable(参见以前的帖子): public static string ToString(Object value, IFormatProvider provider) { IConvertible ic = value as IConvertible; if (ic != null) return ic.ToString(provider); IFormattable formattable = 值作为 IFormattable; if (formattable != null) return formattable.ToString(null, provider);返回值 == 空? String.Empty: value.ToString(); }
      猜你喜欢
      • 1970-01-01
      • 2021-10-15
      • 2012-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-05
      相关资源
      最近更新 更多