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
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.