.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()后再次切换回。

已知或可能的限制

  1. 如果在self上调用的现有ToString()分派到另一个线程以生成字符串(不确定为什么任何实现都应该这样做(,那么代码的某些部分可能会使用另一个"当前线程区域性"集运行,因此在这种情况下,定义的当前区域性不起作用
  2. 如果线程在ToString((调用中的某个位置等待,同时另一个任务被调度到该线程,则该其他任务可能会意外地为其自己的操作获得强制targetCulture(不确定是否是这种情况(
  3. 我不知道切换线程文化的成本是多少——它可能很昂贵

问题

  1. 这个实现使用起来安全吗,或者有可能破坏工作代码的限制吗?(例如,通过切换到其他线程的错误区域性(
  2. 有更好的方法来解决这个问题吗
  3. 或者:是否需要扩展.NET框架API以支持本地化的ToString((

很乐意得到一些想法,

.NET中的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();
    }