Что такое IReadOnlyList в C#?

Ответ

IReadOnlyList — это интерфейс, представляющий контракт на доступ только для чтения к коллекции с поддержкой индексатора. Он гарантирует, что потребитель не сможет изменить саму коллекцию (добавить/удалить элементы), но не защищает от изменения состояния самих объектов внутри коллекции.

Иерархия: IEnumerable<T> -> IReadOnlyCollection<T> -> IReadOnlyList<T>.

Пример использования:

// Метод возвращает защищенную от изменений коллекцию
public IReadOnlyList<string> GetActiveUsers()
{
    List<string> internalList = FetchUsersFromDatabase();
    // Возвращаем как IReadOnlyList, скрывая методы модификации
    return internalList;
}

// Клиентский код
var users = GetActiveUsers();
Console.WriteLine(users[0]); // Доступ по индексу работает
Console.WriteLine(users.Count); // Получение количества работает
// users.Add("NewUser"); // Ошибка компиляции: IReadOnlyList не содержит метода Add

Ключевые моменты:

  • Защита инкапсуляции: Это предпочтительный тип возвращаемого значения для методов, которые должны предоставлять данные, но не позволять их модифицировать. Это делает API более безопасным и предсказуемым.
  • Не гарантирует неизменяемость объектов: Если T — ссылочный тип, его поля могут быть изменены. Для полной иммутабельности нужны неизменяемые типы (record, readonly struct).
  • Производительность: Многие стандартные коллекции (List<T>, Array, T[]) реализуют этот интерфейс, поэтому преобразование происходит без накладных расходов на копирование.
  • Альтернатива IEnumerable: В отличие от IEnumerable<T>, IReadOnlyList<T> явно сообщает о возможности доступа по индексу и о наличии свойства Count, что делает контракт API более информативным.

Ответ 18+ 🔞

А, слушай, ну это ж классика, блядь! IReadOnlyList — это как твоя теща, которая пришла в гости и говорит: «Смотри, но не трогай, сука!»

Понимаешь, это такой интерфейс, который орет на тебя: «Читать можно, а хуярить внутрь — нет!» То есть ты можешь смотреть на коллекцию, считать элементы, пальцем показывать — «дай мне вот этот, пятый по счёту» — но вот сунуть туда свой новый элемент или выкинуть старый — нихуя. Не-а.

Смотри, как оно по родне идёт: сначала просто IEnumerable<T> — с него можно только вытягивать данные, один за другим. Потом IReadOnlyCollection<T> — к нему добавили свойство Count, чтобы ты заранее знал, сколько тебе выгребать придётся. А IReadOnlyList<T> — это уже топчик, к нему ещё и индексатор прикрутили, чтобы ты мог по номеру, как в столовой, тыкать: «дай мне тот, что в синей чашке, на третьей полке!»

Вот, смотри, как на практике выглядит, чтоб не пиздеть просто так:

// Допустим, у тебя внутри метода своя кухня, свои списки
public IReadOnlyList<string> GetActiveUsers()
{
    List<string> internalList = FetchUsersFromDatabase(); // тут ты наковырял из базы
    // А возвращаешь как IReadOnlyList, чтобы умники снаружи не накосячили
    return internalList; // вот это преобразование — оно бесплатное, блядь!
}

// А потом где-то в коде:
var users = GetActiveUsers();
Console.WriteLine(users[0]); // Всё, прочитал первого юзера — молодца
Console.WriteLine(users.Count); // Узнал, сколько их всего — умничка
// users.Add("NewUser"); // А вот это попробуй — компилятор тебе ебальник набьёт! IReadOnlyList не умеет добавлять, он же ReadOnly, ёпта!

Важный момент, который все просрать могут: этот интерфейс защищает саму коллекцию от изменений. То есть список не пополнишь и не почистишь. Но! Если внутри лежат объекты — ссылочные типы — то их внутреннее состояние менять можно, блядь! Представь: тебе выдали список аквариумов только для чтения. Сам ты аквариум выкинуть или новый поставить не можешь, а вот рыбок внутри каждого аквариума потрогать — запросто, хоть воду мути. Для полной, блять, неприкосновенности нужны иммутабельные типы, вроде record или readonly struct.

И ещё: это часто лучше, чем просто IEnumerable<T> возвращать. Потому что IEnumerable — он как тёмная комната: «иди, щупай, может там что-то есть». А IReadOnlyList — он уже свет включает и говорит: «вот, смотри, тут ровно 15 штук, и к каждой можно по индексу подойти». API сразу честнее и понятнее становится.

Короче, юзай его, когда хочешь данные наружу выдать, но при этом боишься, что их нахуй раздербанят.