IList
3 min readIList
TL;DR
IList<T> extends ICollection<T> with an indexer plus Insert, RemoveAt, and IndexOf, exposing random access at index i. Use it when callers truly need positional reads or insert-at-position semantics (an order book, a price ladder); otherwise prefer the narrower IEnumerable<T> or IReadOnlyList<T> so you don't leak mutability that the API never intended to support.
How it works
IList — Indexed Access Collections
"Use IList
when you need random access by index, or when Insert/RemoveAt operations are required."
❌ Bad example:
public IEnumerable<Trade> GetRecentTrades()
{
return _trades.OrderByDescending(t => t.Timestamp).Take(10);
}
// Caller
public void DisplayLastTrade(IEnumerable<Trade> trades)
{
var lastTrade = trades.Last(); // enumerates entire sequence
Console.WriteLine(lastTrade.Symbol);
}
Using .Last() on IEnumerable
âś… Good example:
public IList<Trade> GetRecentTrades()
{
return _trades.OrderByDescending(t => t.Timestamp).Take(10).ToList();
}
// Caller
public void DisplayLastTrade(IList<Trade> trades)
{
var lastTrade = trades[trades.Count - 1]; // O(1) indexed access
Console.WriteLine(lastTrade.Symbol);
}
👉 IList
🔥 When Insert/RemoveAt matters:
public class OrderBook
{
public IList<Order> BuyOrders { get; } = new List<Order>();
public void InsertOrderAtPrice(Order order)
{
// Binary search to find insertion point
int index = BuyOrders.BinarySearch(order, new PriceComparer());
if (index < 0) index = ~index;
BuyOrders.Insert(index, order); // insert at specific position
}
}
👉 IList
🔥 Avoiding unnecessary copies:
// ❌ Bad: forces caller to know concrete type
public List<decimal> CalculatePrices(List<decimal> basePrices)
{
for (int i = 0; i < basePrices.Count; i++)
basePrices[i] *= 1.05m;
return basePrices;
}
// âś… Good: accepts interface, returns interface
public IList<decimal> CalculatePrices(IList<decimal> basePrices)
{
for (int i = 0; i < basePrices.Count; i++)
basePrices[i] *= 1.05m;
return basePrices;
}
👉 Accepting IList
đź’ˇ In trading systems:
- Use IList
for order books where indexed access is critical for price levels. - Enable efficient batch processing with index-based loops (faster than foreach for large arrays).
- Prefer IEnumerable
unless random access is genuinely needed—narrower contract.
Quick recall Q&A
IList
Not strictly. List
Only if callers need indexed access or Insert/RemoveAt. Otherwise, IEnumerable
Yes. Arrays are fixed-size, so Add/Remove throw NotSupportedException. Check IsReadOnly before assuming mutability. Prefer IReadOnlyList
Arrays implement IList
Use for (int i = 0; i < list.Count; i++) when you need the index or modify elements by index. Use foreach for clarity when index isn't needed.
O(n) for List
Yes. Arrays implement IList
Use List
Throws IndexOutOfRangeException (arrays) or ArgumentOutOfRangeException (List