为什么 List<T>.Count 是一个有符号整数? List<T>.Count 可以是负数吗?

Why is List<T>.Count a signed int? Can List<T>.Count ever be negative?

public class List<T>
{
     public int Count
        {
            get;
        }
}

我注意到Count是一个int,结果会小于0吗?

如果Count可以小于0,我必须写成:

if(myList.Count < 1)
{
  
}

否则我可以这样写:

if(myList.Count == 0)
{
  
}

不,那个属性的reference source(仅适用于.NET Framework)是

public int Count {
   get {
       Contract.Ensures(Contract.Result<int>() >= 0);
       return _size; 
   }
}

由于 Contract.Ensures 的工作原理,保证它永远不会 return 小于零。

至于.NET Core,那属性就是

public int Count => _size;
根据代码中的所有分配,

_size 本身永远不会低于零。

当然可以,何必问呢。这里有一些亵渎:

[TestFixture]
public class TotalGarbageTests
{
    [Test]
    public void Blasphemy()
    {
        var list = new List<int>();
        list.GetType().GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(list, -666);
        Assert.AreEqual(-666, list.Count);
    }
}

PS 现在你可能被知识腐蚀了,但是,嗯,不管怎样。

来自评论:

Just to be on the safe side, because I noticed the Count is a int but not a uint

TL;DR:

设计List<T>class时,微软的.NETclass库设计规则意味着UInt32(又名uint)不能使用对于任何 public 成员,因此使用 Int32(又名 int)。


更长的答案:

  • 为什么 Countint(又名 Int32)属性 而不是 uint(或 UInt32)属性 是因为 List<T> 类型是在 Microsoft 仍然遵守公共语言规范(“CLS”)时定义的。
    • 从表面上看,可再分发和可重用的库应该只使用 CLS 批准的数据类型,并且应该避免使用不符合 CLS 的数据类型。
      • Int32 符合 CLS。
      • UInt32 CLS 兼容。
    • CLS 的存在是因为(当时,大约在 2000-2005 年)Microsoft 有这个 宏伟的设计 用于使用 .NET/CLR 作为运行时 许多完全不同的 编程语言的底层类型系统——不仅是 C# 和 VB.NET,还有 Java(yup), OCaml-style functional languages like F#, and even JavaScript, Python, and PHP .
    • ...其中许多语言 不支持 无符号整数类型;事实上,high-profile languages like Java still don't support unsigned types.
    • ...因此,为了 适应 受虐狂使用的语言,例如 Java,主要的 .NET class 库必须设计为对他们可以使用的可能数据类型的限制,这意味着他们必须使用有符号整数来表示无符号值。
    • 因此,如果 Count 被输入为 UInt32 而不是 Int32 那么那些其他语言的用户根本不能使用 List<T>.Count .
  • 自从 .NET Core 发布以来,我不认为有任何官方反对公共语言规范,但即使微软没有正式放弃它,.NET 生态系统的其他部分似乎已经.

List<T>.Count 可以为负数或其他无效吗?

如果您以安全的方式使用 List<T> 实例,那么 不会 .Count 属性 将始终 return 02^31 范围内的值 (the actual maximum count of a List<T> is a different question which is already answered here).

但是,如果您以 线程不安全 方式使用 List<T>(例如有 2 个或更多线程同时在列表中添加和删除项目而不使用lock 正确),或者如果你使用像反射这样的技巧来覆盖 .Count 属性 的字段值然后 yes,你可以破坏东西。所以不要那样做:)

通用语言规范 (CLS)

The motivation for the CLS is described in this article:

  • To enable full interoperability scenarios, all objects that are created in code must rely on some commonality in the languages that are consuming them (are their callers).
  • Since there are numerous different languages, .NET has specified those commonalities in something called the Common Language Specification (CLS).

The Common Language Specification is described in this MSDN article,它有一个 .NET 内置的类型列表,但是 verboten 用于符合 CLS 的框架和可再发行库。

  • System.SByte 又名 sbyte
    • 带符号的八位字节值。
    • 这是唯一的有符号,与 CLS 禁止的无符号类型相反。
    • 奇怪的是,Java实际上有一个signed字节类型。
  • System.UInt16 又名 ushort.
  • System.UInt32 又名 uint.
  • System.UInt64 又名 ulong.
  • System.UIntPtr.

还有:

  • The rules for CLS compliance apply only to a component's public interface, not to its private implementation.
  • For example, unsigned integers other than Byte are not CLS-compliant [...].