Почему у объекта нет перегрузки, которая принимает метод 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
?
Ответы
Ответ 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")