使用uint或int

10

我确实知道无符号整数(uint)和有符号整数(int)之间的基本区别。

我注意到在.NET公共类中,一个名为Length的属性总是使用有符号整数。

也许这是因为无符号整数不符合CLS标准。

但是,在我的静态函数中:

public static double GetDistributionDispersion(int tokens, int[] positions)
参数tokenspositions 中的所有元素都不能为负数。如果为负数,则最终结果将无用。因此,如果我对tokenspositions均使用int,则每次调用此函数时都必须检查值(如果发现负值,则返回无意义的值或引发异常???),这很繁琐。
好吧,那么我们应该为两个参数都使用uint。这对我来说真的很有意义。
然而,我发现在许多公共API中,它们几乎总是使用int。这是否意味着在他们的实现内部,他们始终检查每个值(如果应该是非负数)的负性?
总之,我该怎么办?
我可以提供两种情况: 1. 此函数只由我自己在自己的解决方案中调用; 2. 此函数将被其他团队中的人用作库。
对于这两种情况,我们应该使用不同的方案吗?
Peter P.S .: 我确实做了很多研究,但仍然找不到不使用uint的理由 :-)

我认为这篇文章:使用int和uint的区别以及何时使用是你问题的答案。 - Ankar
@Ankar,我在发布这个问题之前进行了搜索,并阅读了那篇文章,但它没有提供足够的理由说服我不使用uint - Peter Lee
你可能会遇到无法转换为 uint 类型的输入(例如 -2 等),或者需要检查输入是否大于 0。无论哪种情况,都需要进行一些处理工作。 - David Klempfner
5个回答

5

我看到三个选项。

使用uint。框架没有使用它是因为它不符合CLS标准。但是您必须遵守CLS标准吗?(还有一些不好处理的算术问题;随处转换类型会很麻烦。出于这个原因,我倾向于避免使用uint)。

使用int,但使用合同:

Contract.Requires(tokens >= 0);
Contract.Requires(Contract.ForAll(positions, position => position >= 0));

请明确所需的内容。

创建一个自定义类型,封装该要求:

struct Foo {
    public readonly int foo;

    public Foo(int foo) {
        Contract.Requires(foo >= 0);
        this.foo = foo;
    }

    public static implicit operator int(Foo foo) {
        return this.foo;
    }

    public static explicit operator Foo(int foo) {
        return new Foo(foo);
    }
}

然后:

public static double GetDistributionDispersion(Foo tokens, Foo[] positions) { }

啊,太好了。在我们的方法中,我们不必担心这个问题。如果我们得到一个Foo,那它是有效的。
您要求域中的非负性有其原因。它建模了某个概念。最好将该概念提升为域模型中的正式对象,并封装所有与之相关的概念。

似乎代码契约(无论是标准版还是高级版)不适用于VS Express版本 :-) - Peter Lee
@Peter Lee:我认为那可能是正确的。你也可以使用老式的守卫子句。 - jason
你的意思是类似于 if (tokens < 0) throw new ArgumentException("tokens should not be negative", "tokens") 这样的吗? - Peter Lee

3

我使用 uint

是的,其他答案都是正确的... 但我更喜欢 uint,因为有一个原因:

使接口更加清晰。如果参数(或返回值)是无符号的,那是因为它不能为负数(你见过负数的集合计数吗?)。否则,我需要检查参数,记录参数(和返回值),这些参数不能为负数;然后我需要编写额外的单元测试来检查参数和返回值(哇,还有人会抱怨进行强制转换吗?int 强制转换如此频繁吗?根据我的经验,不是这样的)。

此外,用户需要测试返回的负值,这可能更糟。

我不介意 CLS 兼容性,那么我为什么要介意呢?从我的角度来看,问题应该被反转:当值不能为负数时,我为什么要使用 int 呢?

至于返回负值以提供额外信息(例如错误)的观点:我不喜欢这种 C 风格的设计。我认为可以有一种更现代的设计来完成这个任务(例如使用异常,或者替代性地使用 out 值和布尔返回值)。


你的回答正是我所关心的。也许在仅用于我的解决方案的函数/方法中使用 uint 是一个不错的选择。 - Peter Lee
定义性地说,这主要取决于您的需求。我认为CLS合规是避免无符号类型的唯一足够理由。 - Luca

2

是的,使用int类型。我曾经尝试过使用uint类型,但很快就意识到需要在我的库中进行繁琐的转换,最终又重新回到了int类型。 我想这个决定是基于历史原因的,因为通常情况下,结果为-1表示某种错误(例如在IndexOf函数中)。


1

int。当您需要在不久的将来进行API更改时,它提供了更多的灵活性。例如,负索引通常由Python用于表示从字符串末尾开始的反向计数。

当溢出时,值也变为负数,断言会捕获它。

这是速度与健壮性之间的权衡。


我理解这一点,因为我从其他帖子中得到了这个。但是,如果值不应该为负数,他们的实现是否总是进行负数检查? - Peter Lee
是的,这是一种权衡。如果您不喜欢这样,可以使用属性断言方法[Conditional("DEBUG")],它只会在调试构建上进行检查。顺便说一下,除非您明确声明检查要求,否则uint在运行时根本不会进行任何边界检查。 - Bamboo

1

当你阅读它时,它违反了公共语言规范的规则,但是这个函数会被多少次使用?如果它将与其他方法结合使用,他们通常期望参数为int,这将使您陷入转换值的麻烦。

如果您要将其作为库提供,则最好坚持传统的int,否则您需要隐式地处理可能不会得到正值的条件,这意味着在页面上散布检查。

有趣的阅读 - SO链接


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