重写 ToString() 以进行调试和日志 - 字符串应该本地化吗?

发布于 2024-12-13 17:50:28 字数 4196 浏览 1 评论 0原文

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

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

考虑一个对象,其中包含一个名为 dateDateTime 和一个名为 valuedouble(也可能还有其他字段) ...如果我覆盖该对象的 ToString(),我可能想做类似的事情:

public override string ToString() {
    return "ObjectName[date=" + date + ", value=" + value + "]";
}

但这将包括 date.ToString()的结果value.ToString(),这将为我提供本地化的字符串根据Thread.CurrentThread.CurrentCulture

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

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

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

因此,如果我以一种文化不敏感的方式实现我的 ToString() 方法,我觉得我会有点违背常规。但是,当区域性敏感性对于日志文件或调试没有意义时,默认创建区域性敏感的字符串似乎很愚蠢。

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

最重要的是,像 ObjectName[value=12.234, date=2011-10-01] 这样的字符串不应该出现在用户界面中,那么为什么程序员希望对其进行本地化呢? ?

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

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

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

似乎不太适合:

DO 在返回区域性相关信息时根据当前线程区域性进行字符串格式化。

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

我完全支持遵循准则,并编写符合程序员期望的 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();
}

在调试器中运行该测试,当它中断时,您可以看到 DoubleHolder 中包含的 double 被格式化为 . 作为小数分隔符。

然后关闭 Visual Studio,将 Windows 标准和格式区域选项更改为法语,然后再次运行测试。您会看到 doubleString 有一个 , 作为小数分隔符,但调试器仍然在 DoubleHolderdouble code> 和 .

我想在正确的法语版本的 Windows 上使用法语的 Visual Studio 进行测试。在 Visual Studio 中,如果您转到“工具”->“选项->环境->国际设置,您可以将语言设置为“与 Microsoft Windows 相同”。默认情况下,我的安装设置为“英语”。但是要获得法语版的 Visual Studio,您需要安装法语版的 Windows,而我的 Windows 版本似乎只有英语版。如果有人使用法语 Windows 或任何其他使用 , 作为小数点分隔符的语言环境,那么如果您可以检查调试器是否使用 . 或 < code>, 作为格式化双精度数中的小数分隔符。

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

但从上面看来,调试器确实始终使用 . 作为小数点分隔符。对我来说,这意味着与区域性无关的 ToString() 方法很好,如果用于调试目的,可能更可取。

I'm designing a .NET library that will be used by other developers making both web and desktop applications. I'm overriding ToString() in various classes to provide information for debugging purposes and for inclusion in application log files.

Some of my classes contain numbers and dates.

Consider an object that contains a DateTime called date and a double called value (and maybe other fields as well)... If I override that object's ToString(), I might want to do something like:

public override string ToString() {
    return "ObjectName[date=" + date + ", value=" + value + "]";
}

But that will include the result from date.ToString() and value.ToString(), which will give me strings that are localized according to Thread.CurrentThread.CurrentCulture.

And that, to me, seems wrong. The strings returned by my ToString() implementations are meant for debugging and log messages, not for user interfaces. So I think returning localized strings could only confuse matters. If "2,341" appears in log files, a developer would need to know the value of the thread's CurrentCulture to know whether it meant 2 thousand 341 or 2 point 341. It's even more confusing with dates - a string like xx/xx/xxxx could be dd/mm/yyyy or mm/dd/yyyy. I don't want my ToString() methods to create that sort of ambiguity.

So my inclination is to make my ToString() methods culture-insensitive, to ensure that all returned strings are consistent across cultures. For example, internally my ToString() methods would do like value.ToString(CultureInfo.InvariantCulture) to format a number.

However, the norm in .NET libraries seems to be to use CurrentCulture in default no-args ToString() implementations. Many objects that have a ToString() method also have a ToString(IFormatProvider) method as well. It's as if the designers of .NET decided that the default use of ToString() should be for user-interface display (localized), and that debugging and logs (for which you'd need to call ToString(CultureInfo.InvariantCulture)) are secondary.

So if I implement my ToString() methods in a culture-insensitive way, I feel I'd be going against the grain somewhat. But it seems silly to create culture-sensitive strings by default, when culture-sensitivity makes no sense for log files or debugging.

I could use the CurrentCulture to represent numbers and dates in my default ToString() implementations, and also provide ToString(FormatProvider) methods so that people can get a culture-insensitive string for use in log files etc. But that seems dumb as it's just forcing developers to write more code to get the culture-insensitive string that I'm guessing they'll want (whether they've considered it or not).

The bottom line is that a string like ObjectName[value=12.234, date=2011-10-01] shouldn't ever appear in a user interface, so why would a programmer ever want it to be localized?

I've been reading the advice in Framework Design Guidelines on implementing ToString(). Some of the advice seems somewhat contradictory. For example:

I consider ToString an especially dangerous method to provide for UI-generic types, because it's likely to be implemented with some specific UI in mind, making it useless for other UI needs. To avoid tempting myself in this way, I prefer to make my ToString output as geeky as possible to emphasize that the only "humans" that should ever see the output are "developer humans" (a subspecies all their own).

and

The most important value of ToString is that the debugger uses it as the default way of displaying the object.

don't really seem to fit with:

DO string formatting based on the current thread culture when returning culture-dependent information.

and

use the CultureInfo instance returned by a thread's CurrentCulture property to format any numeric or date

I'm all for following the guidelines, and writing APIs that do what programmers expect. But if ToString() is for programmers, then it seems silly to localize it. The C# compiler won't let a programmer write a double literal using a system-dependent decimal separator, so surely ToString() methods written for programmers should behave similarly?

What do you think? When the output from ToString() is not intended for use in a user-interface, should the numbers and dates within it be localized or not?


Update

I did some tests using the DebuggerDisplay attribute, and it looks like, by default, it formats numbers in a culture-insensitive way.

[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 that test in the debugger and, when it breaks you can see that the double contained in DoubleHolder is formatted with a . as a decimal separator.

Then close Visual Studio, change your windows Regional Options for Standards and Formats to French, say, and run the test again. You'll see that doubleString has a , as the decimal separator, but the the debugger still shows the double in DoubleHolder with a .

I would have liked to test this on a proper French version of Windows, with Visual Studio in French. In Visual Studio, if you go to Tools -> Options -> Environment -> International Settings, you can set the Language to "Same as Microsoft Windows". By default on my installation it was set to "English". But to get Visual Studio in French you need to have Windows in French, and my version of Windows seems to be English only. If anyone has a French Windows, or any other locale that uses , as a decimal separator, it'd be great if you could just check whether the debugger uses . or , as the decimal separator in formatted doubles.

I'm wondering if Thread.CurrentThread.CurrentUICulture might make a difference to how the Visual Studio debugger shows things, and I'm not sure that setting it like I do above would be the same as running Visual Studio completely in French.

But from the above it does look like the debugger consistently uses . as the decimal separator. This implies to me that a culture-independent ToString() method is fine, probably preferable, if it's intended for debugging purposes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

雨夜星沙 2024-12-20 17:50:28

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

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

至于ToString()的本地化,我会通过机会发表评论。

For debugging you want to look into Debugger Display Attributes, not use ToString().

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

As for localization of ToString(), I will pass on the opportunity to comment.

你是暖光i 2024-12-20 17:50:28

在我看来,这里唯一重要的两件事是:

  • 您已经考虑预期用途,并适当地应用文化,
  • 该行为已被清楚地记录下来

如果其预期用途是记录,然后不变似乎很好。如果预期用途是 IDE 显示,那么我会将其本地化到当前线程。

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

IMO the only two important things here are:

  • that you have thought about the intended usage, and are applying culture appropriately
  • that the behaviour is clearly documented

If the intended usage of this is logging, then invariant seems fine. If the intended usage was IDE display, then I'd leave it localized to the current-thread.

If unsure, consider adding a ToString(CultureInfo) method, and then the caller can do as they wish. In that scenario I'd assume tw default is the current-culture, and that the logging code should explicitly request invariant (perhaps also via IFormattable).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文