为什么Boolean.ToString输出的是"True"而不是"true"?

275
true.ToString() 
false.toString();

Output:
True
False

为什么要使用"True"而不是"true",这有合理的理由吗?它在编写XML时会出现问题,因为XML的布尔类型为小写,也与C#的true/false不兼容(不确定CLS是否兼容)。

更新:

以下是我用于在C#中绕过此问题(用于XML)的非常hacky的方式:

internal static string ToXmlString(this bool b)
{
    return b.ToString().ToLower();
}

当然,这增加了堆栈中的一个方法,但在所有地方都删除了ToLowers()。


1
我想提一下...我刚刚在 MSDN 博客上读到了一些聪明的解决方案,可以在 C# 中将 "True" 反序列化为布尔类型!请参见 http://blogs.msdn.com/helloworld/archive/2009/04/03/workaround-to-deserialize-true-false-using-xmlserializer.aspx。 - Peter
33
我会将return b.ToString().ToLower();替换为return b ? "true" : "false";。这样更简洁、高效,更不依赖理论上可能会受区域设置影响的方法(尽管在当前实现中并未受到影响)。 - Jon Hanna
1
当使用 RestSharp 将对象的公共属性序列化为 QueryString 以进行 REST WebService 调用时,如果 REST API 对 bools 区分大小写(例如 Google Directions API),则这也会非常令人恼火,因为这会导致 API 调用失败。 - Carlos P
9
ToString是.NET Framework中主要的格式化方法。它将一个对象转换为其字符串表示形式,以便于显示。Object.ToString不是一种序列化机制。 :) - Rytmis
1
哦,是的,这种经验让我防范理论风险,即使目前并没有发生。 - Jon Hanna
显示剩余2条评论
7个回答

186
只有微软的人才能真正回答那个问题。不过,我想提供一些有趣的事实;)
首先,MSDN中关于Boolean.ToString()方法的说明如下:
返回值
类型:System.String
如果此实例的值为true,则为TrueString;如果此实例的值为false,则为FalseString。
备注
该方法返回常量“True”或“False”。请注意,XML区分大小写,并且XML规范将“true”和“false”识别为有效的布尔值集。如果要将ToString()方法返回的String对象写入XML文件,则应首先调用其String.ToLower方法将其转换为小写。
这里是有趣的事实#1:它根本没有返回TrueString或FalseString。它使用硬编码的文字“True”和“False”。如果它使用字段,那么就没有任何好处,因为它们被标记为只读,所以无法更改它们。
替代方法Boolean.ToString(IFormatProvider)甚至更有趣:
备注
提供程序参数已保留。它不参与此方法的执行。这意味着Boolean.ToString(IFormatProvider)方法与大多数具有提供程序参数的方法不同,不反映特定于文化的设置。
解决方案取决于您要做什么。无论您要做什么,我敢打赌都需要一个hack ;)

3
请纠正我如果我错了,但我没有看到Boolean.ToString()的解释有什么问题。bool.TrueString是一个只读字段,其中包含硬编码文本_"True"。因此,说它返回TrueString与说它返回存储在其中的硬编码文本"True"_是相同的,因为返回字符串总是返回值而不是引用。 - Fernando Neira
25
观察到的结果是相同的,但实现方式不同。 - Vojislav Stojkovic
我想你应该知道通过使用反编译器,所以我可以打赌字面值出现是因为编译时编译器替换了变量...除了_TrueString_不是常量,而只是一个只读变量 - 这是一个重要的细节。因此,你是对的。 - Fernando Neira
1
编译C#代码不会在编译结果中用“True”替换Boolean.TrueString。如果实际使用了Boolean.TrueString,那么可以使用反射来更改Boolean.TrueString以返回小写版本...当然谁知道那会破坏什么。您仍然可以使用反射替换Boolean上的ToString方法,使其返回小写变体。 - Dewey Vozel
2
@FernandoNeira,如果明天硬编码的字面值“TrueString”被更改为小写的“true”,那么方法bool.ToString()仍将返回帕斯卡命名法“True”字面值。 - serge
5
我指责Visual Basic,因为它使用True和False作为字面值。 - mrcrowl

113

由于.NET环境旨在支持多种语言,因此它被设计成能够支持许多语言。

System.Boolean(在mscorlib.dll中)是为了由语言内部使用以支持布尔数据类型而设计的。C#对其关键字采用全小写,因此为'bool'、'true'和'false'。

然而,VB.NET采用标准大小写,因此为'Boolean'、'True'和'False'。

由于这些语言必须协同工作,因此不能有true.ToString()(C#)与True.ToString()(VB.NET)产生不同的结果。CLR设计者选择了ToString()结果的标准CLR大小写符号。

布尔值true的字符串表示形式被定义为Boolean.TrueString。

(System.String也存在类似情况:C#将其表示为'string'类型)。


6
从情况看来,他们不得不迁就VB。 - Chris S
5
我会说C#是一门“奇怪”的编程语言。在.NET中,所有的公共成员都是驼峰命名法 - System.Boolean、True、System.String等。正是由于C#的C遗产,才导致了String被别名为string,Boolean被别名为bool,True被别名为true等。(尽管我个人仍然更喜欢C#)。 - stusmith
4
此外,我认为转换为小写字母很容易,特别是在使用VB时,要将其转换为驼峰式则较为困难,就像@John Burns所说的那样。否则,VB用户无法并且永远不会使用ToString(),他们只能像这样强制使用If(b, "True", "False")。因此,像我这样的C#用户需要牺牲使用ToLower() :) - CallMeLaNN
2
@MarkLopez 您的评论是不正确的,请参见此处:http://msdn.microsoft.com/en-us/library/c8f5xwh7.aspx。此外,查找布尔定义会发现它实际上是一个结构体,并且两者具有相同的属性。 - tsemer
2
尽管你的回答有所启发,但我不明白为什么“True”比“true”更“标准”。似乎后者更受欢迎。 - Slight
显示剩余4条评论

60

6
这似乎是最优雅的方法。无需额外编程,使用专门用于XML输出目的的官方库。 - Nyerguds

30

将字符串转换为全小写字母的代码很简单。

但是,将"true"转换回"True"就没有那么简单了。

true.ToString().ToLower() 

这是我用于生成XML输出的方法。


除了@stusmith的答案之外,因为要支持多种语言,这是微软更喜欢VB布尔ToString()结果的好理由。 - CallMeLaNN
@Damieh:实际上,问题是“为什么”。与此不同的是,所选答案实际上尽可能接近回答这个问题。 - Nyerguds
1
更好的方法是使用 ToLowerInvariant() - vulcan raven
3
您可以使用System.Globalization.CultureInfo.InvariantCulture.TextInfo.ToTitleCase将"true"转换回"True"。 - Krisztián Balla
@vulcanraven 在这种情况下,这完全没有任何影响。Boolean.ToString()总是返回"True"或"False",在没有不变量的情况下完美地工作。 - GoldenretriverYT
@GoldenretriverYT,请查看代码生成器ToLower()会额外调用GetCurrentThreadNative()get_CurrentCulture(),您可以使用ToLowerInvariant()来避免这些调用。 - vulcan raven

8

它为什么不兼容C#?Boolean.Parse和Boolean.TryParse是不区分大小写的,解析是通过将值与“True”和“False”进行比较来完成的,这些都是Boolean.TrueString或Boolean.FalseString。

编辑:当查看反射器中的Boolean.ToString方法时,发现字符串是硬编码的,因此ToString方法如下:

public override string ToString()
{
    if (!this)
    {
        return "False";
    }
    return "True";
}

27
哇……这可能是C#中唯一一个允许使用构造语句“if (!this)” 的上下文! - Tamas Czinege
2
所以我在问为什么它没有返回“false” - Chris S
1
这是一个奇怪的做法...我的意思是反转条件。 - nicodemus13
6
“那可能是C#中唯一一个使用语句“if (!this)”有效的上下文!你挑战了我,你失败了。https://gist.github.com/Steinblock/10df18afb948866be1ba - 此外,今天是乔治·布尔的第200个生日。” - Jürgen Steinblock
为什么不用 return this ? "True" : "False"; 呢?(另一个不寻常的情况是你不经常看到 this 作为 ?: 条件,但在这里它是有意义的。) - Darrel Hoffman

7

我知道它为什么会变成现在这个样子,但是当涉及到“自定义”布尔格式化时,我有两种扩展方法已经离不开了:-)

public static class BoolExtensions
{
    public static string ToString(this bool? v, string trueString, string falseString, string nullString="Undefined") {
        return v == null ? nullString : v.Value ? trueString : falseString;
    }
    public static string ToString(this bool v, string trueString, string falseString) {
        return ToString(v, trueString, falseString, null);
    }
}

使用非常简单。以下代码将各种布尔值转换为它们的葡萄牙表示:

string verdadeiro = true.ToString("verdadeiro", "falso");
string falso = false.ToString("verdadeiro", "falso");
bool? v = null;
string nulo = v.ToString("verdadeiro", "falso", "nulo");

你可以使用扩展方法来扩展一个类或接口,但不能用它们来覆盖。与接口或类方法具有相同名称和签名的扩展方法将永远不会被调用。在编译时,扩展方法始终比类型本身中定义的实例方法优先级低。你的解决方案是否有效?(也许ToString()是继承的,因此可以被重写?) - jwize
1
我猜我的上一个评论中的这个签名并没有覆盖任何东西。 - jwize
@jwize 是的,这些是新的签名,所以这是重载而不是覆盖 ;-) - Loudenvier

-1

这可能源自于旧的VB NOT .Net时代,当bool.ToString产生True或False。


4
在.NET之前,VB中的布尔数据类型(实际上是所有数据类型)没有方法。 - Sam Axe
1
在VB6中,您仍然可以将布尔类型转换为字符串(将其分配给字符串变量的最简单方法)。关于这一点奇怪的事情是,转换实际上是与文化相关的。因此,如果运行计算机上的文化语言是挪威语,则结果为“Sann”和“Usann”,而不是“True”和“False”!如果布尔设置存储在文本文件中,并导出到设置为英语(美国)文化的不同环境中的计算机中,这通常会导致问题。 - awe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接