为啥对象没有接受 IFormatProvider 的重载?
Posted
技术标签:
【中文标题】为啥对象没有接受 IFormatProvider 的重载?【英文标题】:Why doesn't object have an overload that accepts IFormatProvider?为什么对象没有接受 IFormatProvider 的重载? 【发布时间】:2011-11-23 04:37:48 【问题描述】:例如,当将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
上没有这种重载有什么好处?
【问题讨论】:
【参考方案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));
【讨论】:
IConvertible
实际上更有意义(除非您打算格式化数字。)
@dlev:我不同意 - OP 特别希望 just 进行格式化。鉴于类型可以轻松实现 IFormattable 但不是 IConvertible,并且 IFormattable 中的单个方法正是 OP 想要调用的方法,我认为 IFormattable 更有意义。
@Jon 根据 OP 的问题,他似乎有实际使用ToString()
的IConvertible
版本的经验,这就是我提到它的原因。不过,你的观点很好。【参考方案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")
【讨论】:
Convert.ToString 实际上强制转换为 IConvertible 和 IFormattable(参见以前的帖子): public static string ToString(Object value, IFormatProvider provider) IConvertible ic = value as IConvertible; if (ic != null) return ic.ToString(provider); IFormattable formattable = 值作为 IFormattable; if (formattable != null) return formattable.ToString(null, provider);返回值 == 空? String.Empty: value.ToString();以上是关于为啥对象没有接受 IFormatProvider 的重载?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Array.prototype.reduce() 不接受 Map 对象作为初始值?
为啥类型 `Record<string,unknown>` 不接受具有已定义键的对象作为值
StreamWriter 和 IFormatProvider