为什么对象没有一个接受IFormatProvider的重载?

本文关键字:IFormatProvider 重载 对象 有一个 为什么 | 更新日期: 2023-09-27 18:09:36

例如,当将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上没有这个重载有什么好处吗?

为什么对象没有一个接受IFormatProvider的重载?

尝试将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));
    }
}

Peter's solution的便捷扩展方法(修改后也可以测试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();
}

试试这些:

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")