---
title: "How does TryGetNonEnumeratedCount work?"
description: "`TryGetNonEnumeratedCount` attempts to determine the number of elements in a sequence without forcing an enumeration. It returns `true` if it could and `false` if it couldn't. The API was added with .NET 6 - let's have a look at how that thing works."
updated: 2023-05-26
tags: [".NET", "C#"]
canonical: "https://steven-giesel.com/blogPost/c341ffbc-d816-49ca-82a7-0e0e3b3e5910/how-does-trygetnonenumeratedcount-work"
---

# How does TryGetNonEnumeratedCount work?

`TryGetNonEnumeratedCount` attempts to determine the number of elements in a sequence without forcing an enumeration. It returns `true` if it could and `false` if it couldn't. The API was added with .NET 6 - let's have a look how that thing works.

## A simple example
Have a look at the following example:

```csharp
var myEnumeration = new[] { 1, 2, 3, 4 };
var could = myEnumeration.TryGetNonEnumeratedCount(out var count);
```

This one is easy. We have an `Array` and an `Array` has a `Length` property the function could retrieve. So `could` is `true` and `count` is `4`.
Internally `TryGetNonEnumeratedCount` calls `ICollection<T>.Count` if the type implements `ICollection<T>`. `Array` implements `ICollection<T>` so it's easy to get the count.

## A more complex example
Have a look at the following example:

```csharp
var range = Enumerable.Range(1, 4);
var could = myEnumeration.TryGetNonEnumeratedCount(out var count);
```

Still, `could` is `true` and `count` is `4`. But how did that work? `Enumerable.Range` returns an `IEnumerable<int>`, and `IEnumerable<T>` does not have a `Count` property. So, how did `TryGetNonEnumeratedCount` get the count? The magic lies in a special `internal` interface called: `IIListProvider`. The description of said type:

> An iterator that can produce an array or `List<TElement>` through an optimized path.

And guess what? There is a `RangeIterator`. This is the actual type your `Enumerable.Range` method returns. `IIListProvider` has a `GetCount` method which returns the count. So `TryGetNonEnumeratedCount` calls `GetCount` on the `RangeIterator` and gets the count. The method signature is:
```csharp
internal interface IIListProvider<TElement>
{
    int GetCount(bool onlyIfCheap);
}
```

The `onlyIfCheap` parameter is a hint to the implementation that it should only return the count if it's cheap to do so:

```csharp
public int GetCount(bool onlyIfCheap) => unchecked(_end - _start);
```

That is the actual implementation of the method inside the `RangeIterator`. You defined the start and end, so it is easy for the method to calculate how many items it would hold.

## `LINQ` - Let's make it spicey!
Okay, even though that seems straightforward, we can go a bit deeper into the rabbit hole. Let's have a look at the following example:

```csharp
var myEnumeration = Enumerable.Range(1, 4);
var newEnumeration = myEnumeration
    .Order()
    .Select(s => s * s);
var could = newEnumeration.TryGetNonEnumeratedCount(out var count);
```

What do you think `could` and `count` is? `could` is `true` and `count` is `4`. But how did that work? And why does it know the count is four without enumerating? Well, let's have a look from a logical/abstract point of view. We know that `Enumerable.Range` returns a `RangeIterator`, which is an `IIListProvider<int>`. We also know that `Select` or `Order` doesn't change anything in the quantity of our enumeration, so why should I care then?

And that is exactly how it works. We have certain iterators that just look up what the parent does. Let's take the last `Select` statement. The real call looks like this:

```csharp
public int GetCount(bool onlyIfCheap)
{
    if (!onlyIfCheap)
    {
        // ... 
    }

    return _source.GetCount(onlyIfCheap);
}
```

And guess who our `_source` is? It's the `RangeIterator` we already know. So the `Select` iterator just asks the `RangeIterator` for the count. And the `RangeIterator` knows the count because it's an `IIListProvider<int>`.

If we throw in a `Where()` statement the `IIListProvider` has no idea how many items will be returned. It would have to call the `Where` statement on the concrete instance. As this would enumerate, it will return `false` and `count` will not be set.

All in all, it boils down to many internal iterators that represent common operations in the .NET framework that implement `IIListProvider` and can therefore possibly return the count without enumerating. It is a clever way without exposing the internals!

## Special case: `IQueryable<T>`
Short: It doesn't matter what you do by default `IQueryable<T>` will always return `false` and `count` will not be set:

```csharp
var myEnumeration = Enumerable.Range(1, 4).AsQueryable();
var could = myEnumeration.TryGetNonEnumeratedCount(out var count);
```

Even though it looks almost like the above, `TryGetNonEnumeratedCount` will not work here. `IQueryable` is neither an `ICollection` nor does it implement `IIListProvider`. 

## Conclusion
`TryGetNonEnumeratedCount` is a nice addition to the .NET world. It allows you to get the count of an enumeration without forcing an enumeration. This can be useful in certain scenarios. Hope you understand the internals a bit better.