为什么 Convert.ToString(null) 如果你将 null 强制转换会返回不同的值?

124
Convert.ToString(null)

返回

null

正如我所预料的。

但是

Convert.ToString(null as object)

返回

""

为什么它们不同?

2个回答

150

这里涉及到2个重载的ToString

Convert.ToString(object o);
Convert.ToString(string s);
C#编译器会尝试选择与输入最匹配的重载。 null 可以转换为任何引用类型。在这种情况下,stringobject 更具体,因此将被选为赢家。
null as object 中,您已将表达式的类型确定为 object。这意味着它不再与 string 重载兼容,编译器会选择 object 重载,因为它是仅剩的兼容重载。
如何进行这种决策的详细信息在 C# 语言规范的第7.4.3节中有所涉及。

15
好的,所以它使用了一个重载而不是另一个。有道理。但是两个重载应该返回相同的内容吗?顺便加1。 - John MacIntyre
2
@JohnMacIntyre - 这取决于开发团队而不是编译器。 - JonH
8
如果你查看Convert.ToString(string)的实现,它只是一个恒等函数,而Convert.ToString(object)实际上经过了一条更难以跟踪的路径。乍一看,我同意它们应该返回相同的结果,但是BCL中可转换层并不是我很了解的东西,有可能存在这种差异的良好原因(虽然我表示怀疑)。 - JaredPar
我来这里是为了寻找如何将一个空对象转换为一个空字符串。对于其他搜索者的答案是(string)null,或者如果你的对象叫做o,那么就是(string)o - rayzinnz

66

在跟进JaredPar的重载解析回答之后 - 问题仍然存在,“为什么Convert.ToString(string)返回null,而Convert.ToString(object)返回string.Empty?”

答案是...因为文档了这个

Convert.ToString(string)返回“指定的字符串实例;不执行任何实际转换。”

Convert.ToString(object)返回“value的字符串表示形式,如果value为null,则返回String.Empty。”

编辑: 至于这是否是“规范中的错误”、“非常糟糕的API设计”、“为什么要这样指定”,等等。-我会尝试解释一下为什么我认为这不是什么大问题。

  1. System.Convert有将每个基本类型转换为它本身的方法。这很奇怪 - 因为不需要或无法进行转换,所以这些方法最终只返回参数。 Convert.ToString(string)也是如此。我假设这些方法是为了代码生成方案而存在的。
  2. 传递null时,Convert.ToString(object)有3种选择。抛出异常、返回null或返回string.Empty。抛出异常会很糟糕 - 在假定这些被用于生成的代码的情况下尤其如此。返回null要求你的调用者进行null检查 - 再次,在生成的代码中不是一个很好的选择。返回string.Empty似乎是一个合理的选择。其他的System.Convert处理值类型 - 它们有一个默认值。
  • 返回 null 是否更“正确”仍有争议,但 string.Empty 明显更易用。改变 Convert.ToString(string) 意味着违反“无实际转换”的规则。由于 System.Convert 是静态工具类,每个方法可以逻辑上看作是独立的。在真实场景下,很少存在这种行为应该是“令人惊讶”的情况,因此应让可用性胜过(可能的)正确性。

  • 3
    这并没有回答为什么会是这样。说它表现得像这样是因为文件记录了它的行为,这是一种循环论证。 - CodesInChaos
    2
    在我看来,可以公正地说这是非常糟糕的API设计。 - CodesInChaos
    7
    @CodeInChaos这句话并不是重言式,除非你假定文档是基于BCL开发后的可观察行为编写的。我认为这是一个奇怪的假设。换句话说,它不是“文档记录了它的行为”,而是“文档规定了它将会表现出这样的行为”-也就是说,“指定了它要表现出这样的行为”。 - Mark Brackett
    8
    它只是将问题转移到“为什么要指定它以这种方式行事”。 - CodesInChaos
    2
    值得注意的是,从object重载返回null实际上在技术上是可行的。它规定当输入为null时不返回null,但当输入不为null时,它会调用输入的.ToString()方法。该方法可以被覆盖以返回null。这可能不是一个好主意,但它不会违反运行时的任何规则。使用class ToStringNull { public override string ToString() { return null; } },您将从Convert.ToString(new ToStringNull())获得一个null - Jonathan Gilbert
    显示剩余2条评论

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