IEnumerable
Count
Length
C#
.NET

Difference between IEnumerable Count and Length

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

IEnumerable<T> does not have a built-in Length property, and that is where most confusion starts. In .NET, Length, Count, and LINQ Count() look similar from the call site, but they have different costs and apply to different collection types.

Length, Count, and Count()

Length is a property on arrays and a few fixed-size types such as string. It is constant-time because the runtime already knows the size.

csharp
1int[] numbers = { 10, 20, 30, 40 };
2Console.WriteLine(numbers.Length); // 4
3
4string text = "hello";
5Console.WriteLine(text.Length); // 5

Count is also a property, but it belongs to collection interfaces and classes such as List<T>, Dictionary<TKey, TValue>, ICollection<T>, and IReadOnlyCollection<T>.

csharp
var list = new List<int> { 10, 20, 30, 40 };
Console.WriteLine(list.Count); // 4

Count() is different. It is a LINQ extension method for IEnumerable<T>. If the source sequence exposes a fast count through one of the supported collection interfaces, LINQ uses that. Otherwise, it enumerates the entire sequence.

csharp
IEnumerable<int> source = Enumerable.Range(1, 4);
Console.WriteLine(source.Count()); // 4

That last example looks cheap, but the method call can be much more expensive than a property access when the sequence is deferred.

Why IEnumerable<T> Has No Length

IEnumerable<T> only promises one thing: you can iterate over it. It does not promise random access, fixed size, or even repeatable results.

A sequence may come from:

  • a database query
  • a generator using yield return
  • a file stream
  • a network-backed API

In all of those cases, "how many items are there" may require iterating through the whole sequence.

csharp
1static IEnumerable<int> Generate()
2{
3    Console.WriteLine("Starting enumeration");
4
5    for (int i = 1; i <= 3; i++)
6    {
7        Console.WriteLine($"Yielding {i}");
8        yield return i;
9    }
10}
11
12IEnumerable<int> values = Generate();
13int total = values.Count();
14Console.WriteLine(total);

Running this prints each yielded item because Count() consumes the iterator.

Performance Implications

For arrays and lists, prefer the property when you know the concrete type. It communicates intent and avoids unnecessary abstraction.

csharp
1int[] data = { 1, 2, 3, 4, 5 };
2Console.WriteLine(data.Length);
3
4List<int> items = new() { 1, 2, 3, 4, 5 };
5Console.WriteLine(items.Count);

If you only have IEnumerable<T>, Count() is fine when you genuinely need the count and understand the source may be enumerated. Problems start when code calls Count() repeatedly inside loops or on expensive deferred queries.

Bad pattern:

csharp
1IEnumerable<int> query = File.ReadLines("numbers.txt").Select(int.Parse);
2
3for (int i = 0; i < query.Count(); i++)
4{
5    Console.WriteLine(i);
6}

If the source does not expose a fast count, that loop recomputes the count every iteration. Materialize once if needed.

csharp
1List<int> cached = File.ReadLines("numbers.txt")
2    .Select(int.Parse)
3    .ToList();
4
5for (int i = 0; i < cached.Count; i++)
6{
7    Console.WriteLine(cached[i]);
8}

Safe Patterns When You Only Have IEnumerable<T>

If your method accepts IEnumerable<T>, decide whether you need:

  • streaming behavior
  • a count only
  • indexed access

For count only, use TryGetNonEnumeratedCount in newer .NET versions. It avoids enumeration when possible.

csharp
1IEnumerable<int> source = Enumerable.Range(1, 100);
2
3if (source.TryGetNonEnumeratedCount(out int count))
4{
5    Console.WriteLine($"Fast count: {count}");
6}
7else
8{
9    Console.WriteLine($"Enumerated count: {source.Count()}");
10}

If you need indexing or repeated passes, convert to an appropriate collection type first.

csharp
IReadOnlyList<int> values = source.ToList();
Console.WriteLine(values.Count);
Console.WriteLine(values[0]);

That makes the cost explicit instead of hiding it behind repeated LINQ calls.

API Design Guidance

Method signatures matter. If your code needs count and index access, accept IReadOnlyList<T> or ICollection<T> instead of plain IEnumerable<T>.

csharp
1static void PrintSummary(IReadOnlyList<int> values)
2{
3    Console.WriteLine($"Count: {values.Count}");
4    Console.WriteLine($"First: {values[0]}");
5}

This is clearer than accepting IEnumerable<T> and then assuming the sequence can be counted and indexed cheaply.

A stronger signature also helps callers understand what shape of data the method expects.

Common Pitfalls

  • Expecting IEnumerable<T> to have a Length property.
  • Assuming Count() is always constant-time.
  • Calling Count() repeatedly on deferred queries.
  • Accepting IEnumerable<T> in APIs that really require indexing.
  • Forgetting that counting an iterator can consume expensive work.

Summary

  • 'Length is a property for arrays and similar fixed-size types.'
  • 'Count is a property for collection types such as List<T>.'
  • 'Count() is a LINQ method for IEnumerable<T> and may enumerate the source.'
  • Use concrete collection interfaces when your API needs more than simple iteration.
  • Treat counting deferred sequences as potentially expensive unless you know the source.

Course illustration
Course illustration

All Rights Reserved.