开发者

Why doesn't object have an overload that accepts IFormatProvider?

When converting for instance a decimal to a string, you use the CultureInfo.InvariantCulture and pass it as an IFormatProvider. But why is this overload not in object?

A nice implementation would be:

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

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

This would cause no harm or benefit to the object class, but objects deriving from it can instead override the overload and it will be a lot easier to call it when you are unsure of the type.

The problem that made me run into this was when I was making a method that would be getting all properties of a class and writing it to xml. As I didn't want to check the type of the object, I just called ToString. But would this have been a decimal, the output would be based on the CurrentCulture of the thread, which is not optimal. The only workaround I can see is changing the CurrentCulture to InvariantCulture and then changing it back to whatever it was before. But that would just be ugly as I would have to write try finally blocks etc.

My current code is:

        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.WriteElementStrin开发者_JAVA百科g(property.Name, 
                value.ToString());
            }
        }

But I would want it to be:

        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));
            }
        }

Any benefit of not having this overload on object?


Try to cast your value to 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));
    }
}


Handy extension method of Peter's solution (modified to test also for 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();
}


Try one of these:

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

XmlConvert.ToString() is made for XML, so it will keep things closer to the XML spec, such as using "true" instead of "True". However, it is also more brittle than Convert.ToString(). For example, this will throw an exception because of the UTC time:

XmlConvert.ToString(DateTime.UtcNow)

but this works:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜