【问题标题】:Can IEnumerable.Count() return a negative number? [duplicate]IEnumerable.Count() 可以返回负数吗? [复制]
【发布时间】:2018-09-05 06:01:20
【问题描述】:

C# IEnumerable.Count(IEnumerable<TSource>) 和 IEnumerable.Count(IEnumerable<TSource>, Func<TSource,Boolean>) 都返回类型 int 暗示它可以返回小于零的值。这样做没有意义,但如果类型是int,理论上结果可能是负值。

IEnumerable<string> list = GetMyList(); 
int listCount = list.Count(); 

// is it more correct to do this: 
if(listCount <= 0)
{
    DoSomething(); 
} 
else 
{
    DoSomethingElse(); 
} 

// or this: 
if(listCount == 0)
{
    DoSomething(); 
} 
else if (listCount > 0)
{
    DoSomethingElse(); 
} 
else 
{
    // but this branch will never be hit 
    throw new Exception(); 
}

我在网上找不到任何关于这是否真的会发生的信息,Documentation for Enumerable.Count 没有具体说明它可能发生的任何情况。

只是想知道是否有人对这种情况有任何经验或有关此的任何信息。

谢谢

【问题讨论】:

  • 它会返回负数吗?是的。它会返回负数吗? 非常不太可能。 IEnumerable 的一些实现可能是有意义的,但我想不出它在哪里有用。也许在一些流式上下文中,比如响应式扩展。
  • 您如何将 "Returns the number of elements in a sequence." 的负数解释为除了错误之外的任何内容?
  • 发生这种情况的唯一方法是,如果你有实现ICollection&lt;T&gt; 的东西,它的Count 属性返回一个负值,因为Enumerable.Count 会使用它,如果可以的话。否则,它会尝试迭代IEnumerable 并从 0 开始计数项目数。
  • 我有时会担心这个。也许需要一个短期的常识课程。

标签: c# .net linq


【解决方案1】:

返回数据类型的目的不是暗示一个数字范围。尽管它自然地确实设置了一个严格的上限和下限(有点……参见LongCount),但这只是类型兼容性和可推广性的副作用。

考虑数组的Rank 属性。最大值为 32。但我们不会将其存储为字节或短字节。我们将它存储在一个 int 中。为什么?我们并不需要所有的范围。但建议:它们很快(它们与寄存器大小和内存映射很好地对齐),并且按照惯例,It is easier to work with other libraries if you work with ints。此外,int 数据类型是 CLS-compliant(意味着任何实现 CLR 的语言都必​​须支持它)但 uint32 不是。

返回具有特定范围的数值数据类型绝不意味着将使用整个范围。从IEnumerable.Count() 返回一个负值不仅是糟糕的形式,而且在语义上也不正确,因为计数显然必须返回一个cardinal number,它必须是整数且非负数。

【讨论】:

    【解决方案2】:

    实际上在IEnumerable 和IEnumerable&lt;T&gt; 上都没有定义这样的方法Count,而是在静态类System.Linq.Enumerable 上。由于它是 (static) 扩展方法,因此您根本无法覆盖或修改它。那么让我们看看扩展方法:

    public static int Count<TSource>(this IEnumerable<TSource> source)
    {
        if (source == null) throw Error.ArgumentNull("source");
        ICollection<TSource> collectionoft = source as ICollection<TSource>;
        if (collectionoft != null) return collectionoft.Count;
        ICollection collection = source as ICollection;
        if (collection != null) return collection.Count;
    
        int count = 0;
        using (IEnumerator<TSource> e = source.GetEnumerator()) {
            checked {
                while (e.MoveNext()) count++;
            }
        }
        return count;
    }
    

    如您所见,Count永远返回负数的唯一方法是实现 ICollection.Count,由 Enumerable.Count() 调用(如上所示),或通过创建具有完全相同名称的您自己的扩展方法并依赖extension-method resolution 以“隐藏”System.Linq.Enumerable 中的方法:

    public static class MyClass
    {
        public static int Count(this IEnumerable<T> src) { return -1; }
    }
    

    但是我根本看不出有什么理由应该这样做。

    所以简而言之,方法可以返回一个负数。但是,这样做会破坏principle of least astonishment,因此是个坏主意。

    【讨论】:

    • “所以该方法可能永远不会返回负数。” - 它返回一个 Int,我上次检查时是 signed
    • 你只是展示了IEnumerable的扩展,完全有可能第三方库已经实现了它自己的计数,它确实返回了一个负数。
    • @DavidG Count 甚至没有在接口本身上定义,仅在静态类 Enumerable 上定义。所以唯一可行的方法是为此创建自己的扩展方法,不包括System.Linq,还是我错过了什么?
    • 我只是说没那么简单。例如,docs 状态:如果源的类型实现 ICollection,则使用该实现来获取元素的计数。否则,此方法确定计数。
    • @ForeverZer0 实际上,您的答案大多不正确而被否决。
    猜你喜欢
    • 2021-09-21
    • 2013-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-09
    • 1970-01-01
    • 2011-02-04
    相关资源
    最近更新 更多