В C# вы можете удалять элементы из списка с помощью различных методов, таких как `Remove`, `RemoveAt`, `RemoveAll`, и `Clear`. Давайте рассмотрим их более подробно:
1. **Remove**: Удаляет первое вхождение указанного элемента из списка. Если элемент не найден, список остается неизменным.
2. **RemoveAt**: Удаляет элемент по указанному индексу. Если индекс за пределами допустимого диапазона, вы получите исключение.
3. **RemoveAll**: Удаляет все элементы, которые удовлетворяют указанному условию (делегат Predicate). Это означает, что если вы удаляете объекты, базовые ссылки на эти объекты все еще могут существовать в других частях вашего кода. Если объекты в списке содержат ссылки на другие объекты, то эти другие объекты не будут удалены или освобождены из памяти; только ссылки в списке будут удалены.
4. **Clear**: Очищает все элементы в списке, но сам объект списка остается. Все ссылки на объекты в списке будут удалены, но сами объекты не будут освобождены, если на них все еще существуют другие ссылки в вашем коде. Они останутся в памяти до тех пор, пока на них есть хотя бы одна ссылка.
Что касается того, почему после использования методов `RemoveAll` и `Clear` члены остаются равными `null`, это связано с тем, что список просто удаляет ссылки на эти объекты. Если в вашем коде нет других ссылок на удаленные элементы, они станут "висячими", и сборщик мусора может освободить их в будущем.
Поведение описанных методов остается неизменным не только в Unity, но и в любой среде, использующей .NET, так как они являются частью стандартной библиотеки C# (`System.Collections.Generic.List<T>`).
Таким образом, если вам нужно "освободить" память, вам следует следить за тем, чтобы не было других ссылок на удаленные объекты. Удаление элементов из списка не привело к немедленному освобождению этих объектов из памяти, так как сборщик мусора C# управляет памятью автоматически, и он освободит объекты только тогда, когда на них не останется ссылок.