Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can IEnumerable.Count() return a negative number? [duplicate]

Tags:

c#

.net

linq

The C# IEnumerable.Count(IEnumerable<TSource>) and IEnumerable.Count(IEnumerable<TSource>, Func<TSource,Boolean>) both return type int implying it can return a value less than zero. It doesn't make sense for it to do so, but if the type is int it's theoretically possible for the result to be a negative value.

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(); 
}

I can't find any information online about whether or not that can actually happen, and the Documentation for Enumerable.Count does not specify any cases in which it might.

Just wondering if anyone has any experience with this happening or any information on this.

Thanks

like image 221
Alyssa Sallean Avatar asked Oct 21 '25 19:10

Alyssa Sallean


2 Answers

The purpose of the return data type is not to imply a range of numbers. Although it naturally does set a hard upper and lower limit (sort of... see LongCount), that is just a side effect of type compatibility and generalizability.

Consider the Array's Rank property. The maximum value is 32. But we don't store it in a byte or short. We store it in an int. Why? We don't need all that range. But it's recommended: they're fast (they align well to register size and memory maps) and, by convention, It is easier to work with other libraries if you work with ints. Also, the int datatype is CLS-compliant (meaning that any language that implements the CLR must support it) but uint32 is not.

Returning a numeric data type that has a particular range in no way implies that the full range will be used. And returning a negative value from IEnumerable.Count() would not only be poor form, but it would be semantically incorrect, as a count must obviously return a cardinal number, which must be and integer and non-negative.

like image 101
John Wu Avatar answered Oct 23 '25 09:10

John Wu


Actually there´s no such method Count defined on neither IEnumerable nor IEnumerable<T>, but on the static class System.Linq.Enumerable. As it´s a (static) extension-method, you can´t override nor modify this at all. So let´s look into the extension-method:

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;
}

As you can see the only way Count will ever return a negative number is by implelementing ICollection.Count, which is called by Enumerable.Count() (as you can see above), or by creating your own extension-method with the exact same name and relying on extension-method resolution in order to "hide" the method from System.Linq.Enumerable:

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

However I can´t see any reason why one should do this at all.

So in short the method can return a negative number. Doing this however breaks the principle of least astonishment and thus is a bad idea.

like image 30
MakePeaceGreatAgain Avatar answered Oct 23 '25 09:10

MakePeaceGreatAgain