.NET中的ToString-通常和许多类中都缺少本地化选项
本文关键字:本地化 选项 许多类 ToString- 中的 NET | 更新日期: 2023-09-27 18:13:57
问题
我使用的是德语Windows安装,因此在处理对象的字符串表示时,我偶尔会在.NET中发现一些看起来不正常的东西。
最常见的根本问题是当前区域性中某个ToString()
实现与InvariantCulture
(=en_US(不同时的不当行为。
区域性(或CultureInfo
(对数字和日期的格式、使用的语言等进行编码。这种类型的属性有很多:每个线程都有其当前的区域性,UI(在WPF中(有一个或多个。
在对对象调用ToString()
时,通常情况下,当前区域性是您想要的,但有时您希望有一个特定的目标区域性-在许多情况下,如果不进行破解,就不支持进行选择(请参阅下面的"迄今为止我拥有的最佳解决方案"(。
当前状态
由于System.Object
实现了一个基本的ToString()
,许多类都会覆盖它(最好的做法是,只要类名之外有有用的信息可以提供,就立即覆盖它(。
ToString()
的重载存在于许多类中,有些类有一个重载ToString(CultureInfo culture)
,它接受要使用的区域性,但不是全部。
我敢肯定,有些情况不是由(选择的(设计决定的(请参阅下面的Geometry类示例(,但当您想要支持本地化时,使用来自其他对象(不同类型(的派生ToString()
实现的自己的类可能会很有挑战性,因为没有干净的方法可以将Culture向下推到那个调用。
示例:几何图形类
我现在面临的另一个问题是Snoop,它是一个非常有用的工具,可以检查正在运行的程序的任何WPF用户界面。在这里,我检查了一个Geometry
对象,它是ToString()
,我想它应该返回XAML中使用的迷你语言来轻松地对几何体进行编码,但我不能这样使用输出,因为它扰乱了分隔符(en_US的十进制分隔符.
被德语的,
取代,将值彼此分隔的逗号被分号;
取代(。
没有关于ToString((用途的规范,但对我来说,对于en_US文化(我认为这是微软开发人员的主要语言(来说,Geometry.ToString((应该返回一个"可重用"的迷你语言编码,就像你自己在XAML中使用它一样,我不敢相信,使用类似的,但在其他语言中不可用的编码。
到目前为止我拥有的最佳解决方案
有一些未知对象,我想在给定的区域设置中使用字符串表示,我所知道的最好的解决方案包括三个步骤,我不完全确定它们是否可以安全使用:
public string ToStringWithCulture(this object self, CultureInfo targetCulture)
var storedCulture = Thread.CurrentThread.CurrentCulture;
try
{
Thread.CurrentThread.CurrentCulture = targetCulture;
return self.ToString();
}
finally
{
Thread.CurrentThread.CurrentCulture = storedCulture;
}
}
基本原理是将当前区域性切换到之前所需的区域性,并在调用目标对象的ToString()
后再次切换回。
已知或可能的限制
- 如果在
self
上调用的现有ToString()
分派到另一个线程以生成字符串(不确定为什么任何实现都应该这样做(,那么代码的某些部分可能会使用另一个"当前线程区域性"集运行,因此在这种情况下,定义的当前区域性不起作用 - 如果线程在ToString((调用中的某个位置等待,同时另一个任务被调度到该线程,则该其他任务可能会意外地为其自己的操作获得强制
targetCulture
(不确定是否是这种情况( - 我不知道切换线程文化的成本是多少——它可能很昂贵
问题
- 这个实现使用起来安全吗,或者有可能破坏工作代码的限制吗?(例如,通过切换到其他线程的错误区域性(
- 有更好的方法来解决这个问题吗
- 或者:是否需要扩展.NET框架API以支持本地化的ToString((
很乐意得到一些想法,
仅针对object.ToString
限制:
你的方法还不错。但是,通过使用IFormattable
检查,您可以取消切换线程区域性。
public string ToStringWithCulture(this object self, CultureInfo targetCulture)
{
var formattable = self as IFormattable;
return formattable != null ?
formattable.ToString(null, targetCulture) : self.ToString();
}
反射是另一个选项,如果你想在这里格式化ToString。
public static string ToStringWithCulture(this object self, CultureInfo targetCulture)
{
PropertyInfo[] propertyInfos = self.GetType().GetProperties();
var sb = new StringBuilder();
foreach (var prop in propertyInfos)
{
var value = prop.GetValue(self, null) ?? "null";
var formattable = value as IFormattable;
var stringValue = formattable != null ?
formattable.ToString(null, targetCulture) : value.ToString();
sb.AppendLine(prop.Name + " : " +stringValue);
}
return sb.ToString();
}