为什么.NET在某些类中使用int而不是uint?

71

我经常遇到使用 int 来处理 .Count 等内容的代码,即使在框架类中也是如此,而不是使用 uint

这是什么原因呢?

7个回答

76

UInt32 不符合 CLS 兼容性规范,因此可能无法在所有目标通用语言规范的语言中使用。而 Int32 符合 CLS 兼容性规范,因此可以保证在所有语言中都存在。


4
但是为什么这会影响一个人是否使用Int32编写特定语言的代码呢?如果语言X不接受它,但语言Y接受,那么如果我在Y中编程,为什么要关心X呢?这只是为了展示功能而在许多语言中实现的示例,还是有其他原因让我在X的限制下使用Y编程? - Adam Davis
11
“公共语言规范”的想法是让所有编程语言都能使用同一个基础类库。如果基础类库只使用符合CLS的特性,而且所有编程语言都支持这些特性,那么所有编程语言都能使用这个基础类库。同样的道理也适用于你自己写的类库,如果你希望其他语言也能使用它们。” - dtb
7
@Adam:并没有规定你的代码必须遵循BCL所提供的内容。但是,BCL旨在可被任何符合CLS标准的程序集使用,因此BCL必须限制自身仅使用CLS特性。 - Michael Burr

9

在C语言中,int被特别定义为处理器的默认整型类型,因此被认为是执行一般数值操作最快的类型。


1
谢谢Adam,我实际上需要uint的额外范围,但您认为使用它会降低我的应用程序性能吗? - Joan Venge
4
在现代处理器中,无符号整数和有符号整数的性能应该差不多。如果有差异,那么差异很小,如果您需要最大限度地提高性能,那么值得针对您特定的编译器/操作系统/CPU等进行基准测试。 - Adam Davis
7
不会改变程序的性能。为了得到这样的答案,微基准测试是您的朋友(我推荐 MeasureIt)。在我的电脑上,添加 uints 的性能似乎比 ints 快大约 20%(尽管这么小的测量结果并不太可靠)。通常来说,担心这个问题被认为是过早优化;使用最适合情况的方法,并在它导致明显的性能影响后再进行优化。 - Eric Burnett
@AdamDavis:能够容纳任意两个相同符号的Int32值之间算术差异的最小类型是Int32。要容纳两个任意UInt32值之间的差异[自然具有相同的“符号”],则需要一个Int64。在我看来,.NET可能会受益于一个UInt31类型,它可以隐式转换为Int32 - supercat
这不是关于C语言的,而是关于C#的。 - S.S. Anne
@JL2210 正确。这个答案适用于所有可能运行dotnet应用程序的现代处理器,对于两者来说答案都是相同的。 - Adam Davis

6
无符号类型只有在有符号值与无符号值的和或积将成为足以容纳任一操作数的已签名类型,并且如果两个无符号值之间的差异是一个已签名值,足以容纳任何结果时,才会表现得像整数。因此,频繁使用 UInt32 的代码通常需要将值计算为 Int64。当操作数过大时,有符号整数类型的运算可能无法像整数一样运作,但当操作数很小时,它们将表现得很明智。即使操作小型操作数的未提升参数上的操作也会带来问题。例如,给定 UInt32 x;,如果结果类型为 UInt32,则不等式 x-1 < x 将在 x==0 时失败,而如果结果类型为 Int32,则不等式 x<=0 || x-1>=0 将在大的 x 值时失败。只有在类型 Int64 上执行操作时,才能同时保持这两个不等式。

尽管有时定义无符号类型行为以与整数算术不同的方式很有用,但表示像计数之类的事物的值通常应使用将表现得像整数的类型,除非它们比基本整数类型更小,否则无符号类型通常不会这样做。


3

有些东西使用int类型,这样它们就可以返回-1,就像“null”或类似的东西一样。例如,如果ComboBox没有选中任何项,则其SelectedIndex属性将返回-1。


3
这些都很好,但对于负数值来说,.Count 没有意义。 - Joan Venge
6
顺便说一下,那些并不好,真的) SelectedIndex 返回 -1 的原因是第一个 .NET 版本没有可空值。如果找不到或未选择任何内容,强烈建议返回 null。 - EngineerSpock

3

如果可以的话,我会将Count设为UInt16 - 这样只需要一半的空间,但是你仍然可以拥有与Int32一样大的列表... - Philipp M
4
UInt16 不等于 Int32。因为 Int32 中的正整数来自 Int31 范围(而不是 Int16)。 - EngineerSpock

2
如果这个数字本质上是无符号的,那么我会声明它为unsigned int。但是,如果我只是暂时使用一个正数范围内的数字,那么我会称其为int。
主要原因如下:
- 它避免了大量的类型转换,因为大多数方法/函数都是写成以int而不是unsigned int为参数。 - 它消除了可能出现的截断警告。 - 你最终会希望将一个原本应该是正数的数字赋为负数。
以上仅是一些快速的想法。
我曾经试图非常小心地选择正确的unsigned/signed,最后我意识到这并没有真正带来好处,只是增加了额外的工作。所以,为什么要通过混合和匹配使事情变得更难呢?

3
例如,在任何情况下,数据的长度都应该是正数,然而NetworkStream.Read返回一个int? - leumasme
这是一个自我打击的论点,因为索引本质上是正数。 - Denis G. Labrecque

0
一些旧的库甚至使用负数来表示特殊情况,比如 InStr 函数。我相信这要么是因为懒惰,要么是存在负数的特殊值。

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