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

时间:2011-11-05 15:12:03

标签: c# .net api tostring api-design

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

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

考虑一个对象,其中包含名为DateTime的{​​{1}}和名为date的{​​{1}}(也可能是其他字段)...如果我覆盖该对象&# 39; s double,我可能想做类似的事情:

value

但是这会包含ToString()public override string ToString() { return "ObjectName[date=" + date + ", value=" + value + "]"; } 的结果,这会给我根据date.ToString()进行本地化的字符串。

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

所以我倾向于使我的CurrentCulture方法对文化不敏感,以确保所有返回的字符串在不同文化中保持一致。例如,我的ToString()方法内部会像ToString()那样格式化数字。

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

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

我可以使用ToString(CultureInfo.InvariantCulture)来表示我的默认ToString()实现中的数字和日期,还提供CurrentCulture方法,以便人们可以获取对文本不敏感的字符串以供日志使用然而,这似乎是愚蠢的,因为它只是迫使开发人员编写更多代码来获取我猜他们想要的文化不敏感的字符串(无论他们是否已经考虑过它或者不是)。

底线是像ToString()这样的字符串不应该出现在用户界面中,那么为什么程序员会希望它被本地化?

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

  

我认为ObjectName[value=12.234, date=2011-10-01]是一种特别危险的方法来提供UI泛型类型,因为它可能会考虑某些特定的UI而实现,这使得它对其他UI需求毫无用处。为了避免以这种方式诱惑自己,我宁愿尽可能让我的ToString()输出变得令人讨厌,以强调唯一的"人类"应该看到输出是"开发人员" (一个亚种都是他们自己的。)

  

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

似乎并不适合:

  返回与文化相关的信息时,

DO 基于当前线程文化的字符串格式。

  

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

我完全遵循指南,并编写符合程序员期望的API。但如果CultureInfo适用于程序员,那么本地化它似乎很愚蠢。 C#编译器不允许程序员使用依赖于系统的小数分隔符编写双字面值,因此为程序员编写的CurrentCulture方法肯定应该表现得相似吗?

你怎么看? ToString()的输出打算在用户界面中使用时,其中的数字和日期是否应该本地化?


更新

我使用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(); } 的格式为double作为小数点分隔符。

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

我本来希望在适当的法语版Windows上使用法语版的Visual Studio进行测试。在Visual Studio中,如果您转到工具 - &gt;选项 - &gt;环境 - &gt;国际设置,您可以将语言设置为&#34;与Microsoft Windows相同&#34;。默认情况下,我的安装设置为&#34;英语&#34;。但是要用法语获取Visual Studio,你需要使用法语版Windows,而我的Windows版本似乎只是英文版。如果有人使用法语Windows或使用DoubleHolder作为小数点分隔符的任何其他语言环境,那么只要检查调试器是使用.还是,,它就会很棒作为格式化双精度中的小数分隔符。

我想知道.是否可能会对Visual Studio调试器的显示方式产生影响,而且我不确定像上面那样设置它会像运行Visual一样工作室完全用法语。

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

2 个答案:

答案 0 :(得分:16)

要进行调试,您需要查看Debugger Display Attributes,而不是ToString()

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

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

答案 1 :(得分:7)

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

  • 想到预期用途,并正确应用
  • 该行为已明确记录

如果预期的用途是记录,那么不变量就好了。如果预期用途是IDE显示,那么我将其本地化为当前线程。

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