Подтвердить что ты не робот

Почему у объекта нет перегрузки, которая принимает метод IFormatProvider?

При преобразовании, например, a 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 blocks и т.д.

Мой текущий код:

        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?

4b9b3361

Ответ 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));
    }
}

Ответ 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")