Почему объект не имеет перегрузки, которая принимает IFormatProvider? - PullRequest
28 голосов
/ 23 сентября 2011

При преобразовании, например, 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?

Ответы [ 3 ]

29 голосов
/ 23 сентября 2011

Попробуйте разыграть 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));
    }
}
14 голосов
/ 24 октября 2013

Удобный метод расширения решения Питера (изменен для проверки также на 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();
}
8 голосов
/ 18 октября 2014

Попробуйте один из них:

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