我应该在 C# 中将 uint 用于不能为负数的值吗?

Posted

技术标签:

【中文标题】我应该在 C# 中将 uint 用于不能为负数的值吗?【英文标题】:Should I use uint in C# for values that can't be negative? 【发布时间】:2011-01-02 01:21:39 【问题描述】:

我刚刚尝试实现一个类,其中许多长度/计数属性等是uint 而不是int。然而,在这样做的同时,我注意到这样做实际上很痛苦,就好像没有人真正想要那样做。

几乎所有分发整数类型的东西都会返回int,因此需要在几个点进行强制转换。我想构造一个StringBuffer,其缓冲区长度默认为该类中的一个字段。也需要演员表。

所以我想知道我是否应该在这里恢复到int。无论如何,我当然不会使用整个范围。我只是想,既然我正在处理的事情只是不能是负面的(如果是,那将是一个错误),实际使用uint 是一个好主意。

PS:我看到了this question,这至少解释了为什么框架本身总是使用int,但即使在自己的代码中,坚持uint 实际上也很麻烦,这让我觉得它显然不是真正想要的。

【问题讨论】:

另见why-does-net-use-int-instead-of-uint-in-certain-classes 【参考方案1】:

我还要在其他答案中补充一点,使用 uint 作为公共字段、属性、方法、参数等的类型,违反了公共语言规范规则,应尽可能避免。

【讨论】:

我被微软严格遵守。事实证明,IntPtr 应该有一个 uint 构造函数。 如果他们支持自然数,我也会补充一下,例如这种类型的值为 0 到 6,他们可以消除所有数组边界检查,性能大幅提升 5-10%。 利珀特先生,您同意上述说法吗? @AgentFire:该声明声称如果有人做了某事,那将导致特定的性能改进。我没有能力评估反事实的主张;如果您想知道该说法是否属实,请询问 user1496062 是什么证明了他们的说法,而不是我;我不是提出不受支持的主张的人。 @EricLippert 这是你最短的“我不知道”之一,不是吗:p【参考方案2】:

虽然严格来说您应该将uint 用于包含非负整数的变量,但您遇到了它并不总是可行的原因之一。

在这种情况下,我认为必须进行强制转换而降低可读性是不值得的。

【讨论】:

很难说,我不认为强制转换只是索引器会降低易读性,你可以创建一个包装器。变成负数的整数是痛苦且昂贵的错误。 如果你必须为一个 int 创建一个包装器,那么你有更多的可读性问题:)【参考方案3】:

我个人的感觉是,你可能应该坚持使用 int。为了回收 .NET 不太可能让您使用的数字范围,几乎不值得为几乎每个属性访问添加强制转换。

【讨论】:

【参考方案4】:

负值通常用于表示错误情况,操作的大小通常由函数调用返回;因此,负值可能会在不求助于异常机制的情况下发出错误信号。

还要注意,.NET 通常建立在直接的 C 库之上,因此继续这种约定是明智的。如果您需要更大的索引空间,您可以打破不同错误信号机制的约定。

【讨论】:

.NET 与抛出异常而不是返回错误代码非常一致。 -1 返回在托管代码中并不常见。 同意,但我们谈论的是在整个 Windows 技术中普遍存在的设计约定(除了支持它们的例外情况)——与低级代码接口的 .NET 库的那些部分具有在 CRT 错误代码和异常之间进行转换——这是可以理解的,为什么它们提出了 int 的约定而不是 uint 的约定。 @HassanSyed 仍然,如果某些 winapi 返回负值,框架仍然会抛出它自己的异常,将所有内容包装到一个整洁的外壳中,因此该参数在这里不适用。【参考方案5】:

使用 int 也有助于检测操作中的整数溢出。

【讨论】:

不是 100% 准确,如果它溢出以至于达到零。同样,默认情况下启用溢出保护。【参考方案6】:

IMO,使用uint 的缺点是它掩盖了错误情况。以下代码的等价物不太好:

if (len < 0)
    terminate_program("length attained impossible value.");

当然,您的程序一开始就不应该计算错误,但我认为它们也应该被编写成在不传播的情况下快速检测数字错误。在 MaxValue 为 2^31 就足够的情况下,我说使用 int 以及正确使用 System.Diagnostics.Debug.Assert() 和相应的错误检查,如上例所示。

如果您确实使用了uint,请将其与checked 一起使用,以防止下溢并获得相同的结果。但是,我发现将检查应用于出于某种目的使用强制转换的现有代码有点困难。

【讨论】:

【参考方案7】:

如果没有必要,不要逆流而上。不使用强制转换使您的代码更具可读性。此外,如果您的可能值适合 int,则使用 int 不是问题。

如果你担心你可能会溢出一个 int,那么无论如何......但不要过早地优化。

我要说的是,最小化强制转换所提高的可读性胜过使用 int 带来的稍微​​增加的错误风险。

【讨论】:

【参考方案8】:

如果你想检查一个值是否为正,更好的方法可能是使用断言(注意这只是一种调试技术 - 你应该确保这永远不会出现在最终代码中)。

using System.Diagnostics;
...
Debug.Assert (i > 0);

【讨论】:

另见ArgumentOutOfRangeException

以上是关于我应该在 C# 中将 uint 用于不能为负数的值吗?的主要内容,如果未能解决你的问题,请参考以下文章

uint和int的区别

如何在 Swift 中将十六进制转换为有符号浮点数?适用于正数但不适用于负数

C#如何把Int32转换为UInt32。

如何在 C# 中将 IPv4 地址转换为整数?

Int和Uint8 swift之间的区别

如何在MVC C#中将文本框和下拉值从视图传递到控制器