覆盖ToString()以进行调试和日志 - 字符串是否应该本地化?

MB.*_*MB. 8 .net c# api api-design tostring

我正在设计一个.NET库,供其他开发人员使用Web和桌面应用程序.我ToString()在各种类中重写,以提供用于调试目的和包含在应用程序日志文件中的信息.

我的一些课程包含数字和日期.

考虑一个包含DateTime被调用datedouble被调用的对象value(也可能包含其他字段)...如果我覆盖该对象ToString(),我可能想要做类似的事情:

public override string ToString() {
    return "ObjectName[date=" + date + ", value=" + value + "]";
}
Run Code Online (Sandbox Code Playgroud)

但是这将包括来自date.ToString()和的结果value.ToString(),这将给我根据本地化的字符串Thread.CurrentThread.CurrentCulture.

那对我来说,似乎是错的.我的ToString()实现返回的字符串用于调试和日志消息,而不是用户界面.所以我认为返回本地化的字符串只会让事情变得混乱.如果日志文件中出现"2,341",开发人员需要知道线程的值CurrentCulture才能知道它是否意味着2千341或2分341.这对日期更加困惑 - 像xx/xx/xxxx这样的字符串可能是dd/mm/yyyy或mm/dd/yyyy.我不希望我的ToString()方法产生那种歧义.

因此,我倾向于使我的ToString()方法对文化不敏感,以确保所有返回的字符串在不同文化中保持一致.例如,我的ToString()方法在内部就像value.ToString(CultureInfo.InvariantCulture)格式化数字一样.

但是,.NET库中的规范似乎是CurrentCulture在默认的无参数ToString()实现中使用.许多具有ToString()方法的对象也具有ToString(IFormatProvider)方法.就好像.NET的设计者决定默认使用ToString()应该是用户界面显示(本地化),调试和日志(你需要调用它ToString(CultureInfo.InvariantCulture))是次要的.

因此,如果我ToString()以一种对文化不敏感的方式实现我的方法,我觉得我会反对这种方式.但是,当文化敏感性对日志文件或调试没有意义时,默认情况下创建区分文化的字符串似乎很愚蠢.

我可以使用它CurrentCulture来表示我的默认ToString()实现中的数字和日期,并提供ToString(FormatProvider)方法,以便人们可以获得一个文化不敏感的字符串,用于日志文件等.但这似乎是愚蠢的,因为它只是迫使开发人员编写更多的代码来获取我猜他们想要的文化不敏感的字符串(无论他们是否考虑过).

底线是类似的字符串ObjectName[value=12.234, date=2011-10-01]不应该出现在用户界面中,那么为什么程序员会希望它被本地化?

我一直在阅读有关实施的框架设计指南中的建议ToString().一些建议似乎有点矛盾.例如:

我认为ToString提供UI泛型类型是一种特别危险的方法,因为它可能会考虑某些特定的UI而实现,这使得它对其他UI需求毫无用处.为了避免以这种方式诱惑自己,我更喜欢让我的ToString输出尽可能地令人讨厌,以强调唯一应该看到输出的"人类"是"开发人类"(他们自己的亚种).

最重要的值ToString是调试器将其用作显示对象的默认方式.

似乎并不适合:

DO返回文化相关的信息时,基于当前线程的文化字符串格式化.

使用CultureInfo线程CurrentCulture属性返回的实例来格式化任何数字或日期

我全都是为了遵循这些指导原则,编写能够满足程序员期望的API.但如果ToString()是程序员,那么本地化它似乎很愚蠢.C#编译器不会让程序员使用依赖于系统的小数分隔符来编写双字面值,所以ToString()为程序员编写的方法肯定会表现得相似吗?

你怎么看? 当从输出ToString()打算在用户界面的使用,应在它的数字和日期进行本地化或没有?


更新

我使用该DebuggerDisplay属性进行了一些测试,默认情况下,它看起来像是以文化不敏感的方式对数字进行格式化.

[DebuggerDisplay("[value={value}]")]
class DoubleHolder {
    private double value;
    DoubleHolder(double value) {
        this.value = value;
    }
}

[TestMethod]
public void TestDebuggerValue() {
    DoubleHolder s = new DoubleHolder(12345678.12345);
    string doubleString = TestDouble.ToString();
    CultureInfo current = Thread.CurrentThread.CurrentCulture;
    Thread.CurrentThread.CurrentUICulture = current;
    CultureInfo ui = Thread.CurrentThread.CurrentUICulture;
    Debugger.Break();
}
Run Code Online (Sandbox Code Playgroud)

在调试器中运行该测试,当它中断时,您可以看到double包含的内容DoubleHolder是使用.小数分隔符格式化的.

然后关闭Visual Studio,将标准和格式的区域选项更改为法语,然后再次运行测试.你会看到doubleString有一个,作为小数点分隔符,但调试器仍显示doubleDoubleHolder.

我本来希望在适当的法语版Windows上使用法语版的Visual Studio进行测试.在Visual Studio中,如果转到"工具" - >"选项" - >"环境" - >"国际设置",则可以将"语言"设置为"与Microsoft Windows相同".默认情况下,我的安装设置为"英语".但是要用法语获取Visual Studio,你需要使用法语版Windows,而我的Windows版本似乎只是英文版.如果任何人有一个落地窗,或使用任何其他区域设置,作为小数点分隔,这将会是巨大的,如果你可以只检查调试器是否使用.,作为格式化双打小数点分隔符.

我想知道是否Thread.CurrentThread.CurrentUICulture可能会对Visual Studio调试器的显示方式产生影响,而且我不确定像上面那样设置它与使用法语完全运行Visual Studio相同.

但从上面看,它确实看起来像调试器一直.用作小数分隔符.这对我来说意味着文化无关的ToString()方法很好,可能更好,如果它是用于调试目的.

ANe*_*ves 16

对于调试,您需要查看调试器显示属性,而不是使用ToString().

[DebuggerDisplay("{Name} [date={Date}, value={Value}]")]
public class MyClass {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

至于本地化ToString(),我会转发评论的机会.


Mar*_*ell 7

IMO这里唯一的两件重要事情是:

  • 你已经考虑了预期的用途,并正在适当地应用文化
  • 行为清楚地记录在案

如果预期的用途是记录,那么不变量似乎没问题.如果预期的用法是IDE显示,那么我将它本地化为当前线程.

如果不确定,请考虑添加ToString(CultureInfo)方法,然后调用者可以按照自己的意愿执行操作.在那种情况下,我假设tw默认是当前文化,并且日志代码应该明确地请求不变(也许也通过IFormattable).