ICollection
3 min readICollection
TL;DR
ICollection<T> extends IEnumerable<T> with an O(1) Count property plus Add, Remove, Clear, and Contains, so it's the right contract when callers genuinely need a size check or mutation without caring about indexed access. Reach for it instead of IEnumerable<T> to avoid .Count() re-enumerating the whole sequence, but prefer IReadOnlyCollection<T> when you don't intend to expose Add/Remove.
How it works
ICollection — Countable, Modifiable Collections
"Use ICollection
when you need Count without enumeration, and callers may Add/Remove items."
❌ Bad example:
public IEnumerable<Position> GetPositions()
{
return _positions.Where(p => p.IsOpen);
}
// Caller
public void ValidatePositions(IEnumerable<Position> positions)
{
int count = positions.Count(); // enumerates entire sequence
if (count > MaxPositions)
throw new InvalidOperationException("Too many positions");
}
Using .Count() on IEnumerable
âś… Good example:
public ICollection<Position> GetPositions()
{
return _positions.Where(p => p.IsOpen).ToList();
}
// Caller
public void ValidatePositions(ICollection<Position> positions)
{
if (positions.Count > MaxPositions) // O(1) property access
throw new InvalidOperationException("Too many positions");
}
👉 ICollection
🔥 When Add/Remove matters:
public interface IOrderQueue
{
ICollection<Order> PendingOrders { get; }
}
public class OrderProcessor
{
private readonly IOrderQueue _queue;
public void CancelOrder(int orderId)
{
var order = _queue.PendingOrders.FirstOrDefault(o => o.Id == orderId);
if (order != null)
_queue.PendingOrders.Remove(order); // mutation supported
}
}
👉 Callers can modify the collection via Add/Remove without exposing concrete type.
đź’ˇ In trading systems:
- Use ICollection
for position snapshots where count validation is critical. - Expose ICollection
when callers need to add/remove pending orders or alerts. - Prefer IEnumerable
if Count isn't needed—keeps API minimal.
Quick recall Q&A
ICollection
Not strictly, but most implementations (List
Only if callers legitimately need Count or Add/Remove. Otherwise, IEnumerable
Use IReadOnlyCollection
Callers can mutate the collection, potentially breaking invariants. Return defensive copies or IReadOnlyCollection
Arrays implement ICollection
HashSet
No. Count property implies materialization. Returning ICollection
Use List
Depends on implementation. HashSet