为什么在C#中Convert.ToInt32(null)返回0?

41

我今天刚刚发现了这个问题,如果将null转换为int32

Convert.ToInt32(null)

它返回了0。

我原本期望会出现InvalidCastException异常...

有任何想法为什么会这样发生吗?


10
转换并不等同于类型强制转换。 - BoltClock
我必须对这个问题进行负投票,因为答案在方法本身的文档描述中已经清楚地指出。 - Security Hound
是的,文档明确指出将 null 转换为 int32 的结果是 0,但在我的观点中并不太合理,null 对我来说表示的是什么都没有,而不是 0。 - GigaPr
如果您希望在参数为空时出现错误,可以使用Int32.Parse(null)。 - Andre Soares
6个回答

50

你知道为什么会发生这种情况吗?

因为这是文件记录的行为?无论是 Convert.ToInt32(object) 还是 Convert.ToInt32(string), 文件都非常明确地说明:

(在返回值下面)

一个32位有符号整数,等同于 value 中的数字;如果 value 为 null,则为 0 (零)。

或者

等同于 value 的32位有符号整数,如果 value 为 null,则为零。

一如既往,如果现实与期望不符,您应该做的第一件事就是检查您的期望是否符合文件记录的行为。

个人认为,我不完全相信Gavin所展示的“与VB6兼容”的论点。我知道这来自于微软,这可能是它表现出这种方式的真正原因,但我不认为这是一个好的行为原因。有很多VB特定的转换方法-因此,如果框架设计者真正认为返回零是一个不理想的结果,他们应该尽其所能,并提供一个用于VB6程序员使用的VB6兼容转换。

显然,一旦在.NET 1.0中定义了行为,就无法更改以适用于后续版本-但这并不意味着它必须像VB6一样表现。


13

请查看http://msdn.microsoft.com/en-us/library/sf1aw27b.aspx

编辑

上述URL会自动切换到最新的Framework版本,而下面的文本是针对版本4发布的。请参考以下修订后的URL以查看文本。

http://msdn.microsoft.com/en-us/library/sf1aw27b(v=vs.100).aspx

它解释了:

Convert类中的所有字符串转数字的方法如果字符串为空,则返回零。最初的动机是为了为从Visual Basic 6迁移到Visual Basic .NET的程序员提供一组与现有的Visual Basic 6转换方法相匹配的转换方法。假设C#程序员更喜欢强制转换运算符,而Visual Basic传统上使用转换方法进行类型转换。
传统上,.NET Framework试图在版本之间保持高度兼容性。实际上,这意味着,除非有极其强烈的理由,否则一旦一个方法以特定的方式实现并且该实现被公开暴露(例如,方法返回0如果字符串参数为空),则不能更改它,因为这会破坏依赖于已建立行为的代码。这使得你提出的两种解决方案都非常棘手。在第一种情况下,抛出异常会更改客户端依赖于返回空字符串的方法的实现。在第二种情况下,重要的是要记住,.NET Framework不考虑重载分辨率中的返回类型。这意味着您的方法必须替换现有的Convert.ToInt32(String value)方法,并且所有不希望处理可空类型的代码现在都将无法正常工作。
在Convert类中的字符串转数字转换方法的情况下,对兼容性的关注甚至更为强烈,因为Parse是.NET Framework支持的每种原始数值类型执行字符串转数字转换的推荐方法,并且每个Parse方法的行为与其相应的Convert方法不同。与Convert类中的字符串转数字转换方法不同,如果要转换的字符串为空,则每个Parse方法都会引发ArgumentNullException异常,这是您正在争论的行为。数值Parse方法的重载,例如Int32.Parse和Double.Parse,还具有允许对解析操作进行更细粒度控制的优势。

@xanatos:问题在哪里声明了 Convert.ToInt32(object)? 它谈论了值为 null,这意味着它可能是两个重载函数之一。 - Jon Skeet
@xanatos 奇怪的是,如果你输入 Convert.ToInt32(null) 并按 F12 键,它会带你到字符串重载,而 Convert.ToInt32((object)null) 则会带你到对象重载。个人认为编译器应该会对此抱怨,但我没有记住解决步骤。 - Adam Houldsworth
1
@AdamHouldsworth:这一点并不奇怪 - 这就是重载解析的工作原理,因为从nullstringnullobject之间存在转换(所以两者都是候选方法),以及从stringobject的转换,但没有从objectstring的转换(所以转换为string是一种“更好”的转换)。顺便说一下,这是重载,而不是覆盖。 - Jon Skeet
@JonSkeet 是的,我知道它是重载了,我只是打错了单词。所以当提供了null时,它会选择最派生的重载?话说,我刚试了一下我的方法,它选择了非“object”路线,我没有意识到它处理对象就是这样的——我之前预期的是模棱两可的调用错误(当指定另一个引用类型的重载时我会得到这个错误)。 - Adam Houldsworth
听起来是个好答案,但点击链接并没有跳转到你引用的文本。这段文本被删除了吗,还是你捏造了它? - JDB
我发布的URL是针对框架的v4版本,但现在已经推出了4.5版本,相同的文本不再适用。已更新以包含正确的URL。 :) - Gavin

5

因为 Int32 的默认值是零。Int32 是值类型而非引用类型,因此无法为 null,你会得到默认值。


4
好的,这个方法本来可以被记录为返回1,或int.MinValue等值。 - Jon Skeet
2
Int32的默认值为零与Int32不能为null(除非您将其可空)以及当提供null值时,所涉及的方法变为0有什么关系?正如Jon指出的那样,如果您指出的原因确实是原因,他们可能会返回int.MinValue并确保将其转换为非签名整数。 - Security Hound

5

因为这是文档记录的返回结果。也许你在想(int)null,它会抛出NullReferenceException异常(不是InvalidCastException异常,我不确定为什么)。


(int)null 给我返回了 *"error CS0037: Cannot convert null to 'int' because it is a non-nullable value type"*。(int)(string)null 也无法编译,结果是 *"error CS0030: Cannot convert type 'string' to 'int'"*。另一方面,int.Parse(null) 抛出 ArgumentNullException,这是合适的。 - Marc.2377

4

因为这是在Convert类中编写该方法的方式。如果参数值为null,则只会返回0。

public static int ToInt32(object value)
{
    if (value == null)
    {
        return 0;
    }
    else
    {
        return ((IConvertible)value).ToInt32(null);
    }
}

2

如果你遇到了InvalidCastException,那么你很可能进行了一个不受控制的强制类型转换

比如说:

int i = (int)null;

如果您执行它,应该会触发异常。
使用的是


Convert.ToInt32(var)

当你不信任 var 中的值时,比如读取数据库时,这个方法就会很有用。


如果我尝试 int i = (int)null,就会在编译时出现错误。它曾经能够工作吗? - Marc.2377

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