C# и .NET углублённо
Как устроен CLR, память и GC, типы, async/await, LINQ, дженерики, многопоточность и современные возможности C#.
Продолжение «Основ C#». Здесь проверяют уже не синтаксис, а понимание того, что происходит под капотом: где живёт объект, когда его соберёт GC, во что компилятор превращает async, почему IQueryable превращается в SQL.
Рекомендуемый порядок: платформа → память и GC → типы → async/await → коллекции и LINQ → делегаты и события → производительность (Span) → многопоточность.
- 1 Чем отличается .NET Framework от .NET Core / .NET 5+? .NET Framework (1.0–4.8.1) — только Windows, устанавливается в систему целиком, одна версия на машину, развивается лишь исправлениями безопасности. .NET Core → .NET 5+ —… Junior6 мин
- 2 Как работает сборщик мусора (GC) в .NET: поколения, LOH, финализация? GC — трассирующий, поколенческий, компактирующий сборщик: он находит живые объекты от корней (стек, статики, регистры, GC handles), всё остальное считается мусором. Три … Middle10 мин
- 3 Что такое managed vs unmanaged память? Когда нужен IDisposable? Managed — объекты в управляемой куче CLR; их освобождает GC автоматически. Unmanaged — всё, о чём GC не знает: файловые дескрипторы, сокеты, соединения с БД, нативная па… Junior6 мин
- 4 Value types vs reference types: стек, куча, boxing/unboxing, struct vs class? Value type (struct, int, DateTime, enum) хранит сами данные; при присваивании и передаче в метод копируется целиком. Reference type (class, string, массивы, делегаты) — … Junior7 мин
- 5 Как работает async/await под капотом? Что такое SynchronizationContext? Компилятор превращает async-метод в конечный автомат (state machine): код режется на части в точках await, локальные переменные становятся полями структуры. await провер… Middle7 мин
- 6 Разница Task, ValueTask, Thread, ThreadPool? Thread — настоящий поток ОС: свой стек (~1 МБ), дорогое создание. Нужен редко — для долгой выделенной работы с особыми требованиями (приоритет, STA, foreground). ThreadP… Middle6 мин
- 7 Что такое IEnumerable vs IQueryable? Где используется каждый? IEnumerable<T> — последовательность в памяти. LINQ-методы принимают делегаты (Func<T,bool>) и выполняются в вашем процессе (LINQ to Objects). IQueryable<T> — описание за… Junior5 мин
- 8 Как работает LINQ: отложенное выполнение, деревья выражений? LINQ-операторы вроде Where, Select, OrderBy не выполняются сразу — они строят цепочку итераторов (или дерево выражений для IQueryable). Выполнение происходит при перечис… Middle6 мин
- 9 Generics: constraints, covariance/contravariance (in/out)? Generics — параметризованные типы и методы: типобезопасность на этапе компиляции, без приведения типов и без boxing для значимых типов. Ограничения (where T : ...) сообщ… Middle6 мин
- 10 Delegates, Action, Func, Predicate — разница и применение? Делегат — типобезопасная ссылка на метод (или несколько методов). Под капотом — класс, наследник MulticastDelegate, хранящий объект-цель (Target) и указатель на метод. A… Junior5 мин
- 11 Что такое events, multicast delegates, утечки памяти через события? event — обёртка над полем-делегатом, которая снаружи разрешает только += и -=. Вызвать событие или перезаписать список подписчиков может только класс-владелец. Делегат с… Middle5 мин
- 12 Span<T>, Memory<T>, ArrayPool — зачем и когда? Span<T> — ref struct, «окно» в непрерывную память (массив, стек через stackalloc, нативная память) без копирования и аллокаций. Живёт только на стеке: нельзя в поле клас… Senior6 мин
- 13 Reflection vs Source Generators — разница, производительность? Reflection — анализ и вызов типов во время выполнения: GetType(), GetProperties(), MethodInfo.Invoke, Activator.CreateInstance. Гибко, но медленно (проверки, boxing, нет… Senior5 мин
- 14 Атрибуты: создание, чтение через Reflection, компилируемые атрибуты? Атрибут — декларативные метаданные, прикреплённые к сборке, типу, методу, свойству, параметру. Сам по себе атрибут ничего не делает — его читает кто-то другой: компилято… Middle6 мин
- 15 Что такое record types и positional records в C# 9+? record (= record class) — ссылочный тип с равенством по значению: два record равны, если равны все их поля. Positional record record Person(string Name, int Age); — комп… Junior6 мин
- 16 Pattern matching: switch expressions, property patterns, when guards? Pattern matching — проверка «имеет ли значение определённую форму» с одновременным извлечением данных: if (obj is Order { Total: > 1000 } o). Switch expression (C# 8) — … Middle5 мин
- 17 Nullability annotations и nullable reference types в C# 8+? Nullable reference types (NRT) — режим компилятора (<Nullable>enable</Nullable>), в котором string означает «не может быть null», а string? — «может быть null». Это толь… Junior6 мин
- 18 Что такое stackalloc и unsafe код — когда оправдано? unsafe разрешает указатели (int*), адресную арифметику, fixed, sizeof для любых unmanaged-типов. Требует <AllowUnsafeBlocks>true</AllowUnsafeBlocks>. Проверки границ и т… Senior5 мин
- 19 Как работает интерфейс IAsyncEnumerable<T>? IAsyncEnumerable<T> (C# 8) — асинхронная последовательность: элементы приходят по одному по мере готовности, а ожидание каждого не блокирует поток. Потребление: await fo… Middle5 мин
- 20 CLR JIT vs AOT компиляция — отличия, NativeAOT? C# компилируется в IL (промежуточный язык). Превратить IL в машинный код можно во время выполнения (JIT) или заранее (AOT). JIT (RyuJIT): компилирует метод при первом вы… Senior5 мин
- 21 Примитивы синхронизации: lock, Monitor, Mutex, SemaphoreSlim, ReaderWriterLockSlim, Interlocked? lock (= Monitor.Enter/Exit в try/finally) — взаимное исключение внутри процесса; быстрый (спин + ожидание), реентерабельный. Нельзя await внутри. В .NET 9 появился тип S… Middle6 мин
- 22 volatile, Interlocked, Memory Barriers — когда нужны? Компилятор, JIT и процессор могут переупорядочивать операции чтения/записи и кэшировать значения в регистрах — в однопоточном коде это незаметно, в многопоточном ломает … Senior6 мин
- 23 ConcurrentDictionary, ConcurrentQueue, ImmutableDictionary — когда что? ConcurrentDictionary<K,V> — потокобезопасный словарь: чтение без блокировок, запись блокирует только один сегмент (stripe). Атомарные GetOrAdd, AddOrUpdate, TryUpdate. Л… Middle7 мин
- 24 ExecutionContext, AsyncLocal и SynchronizationContext: как контекст «течёт» через await? ExecutionContext — «окружение» логического потока выполнения: значения AsyncLocal<T>, контекст безопасности, культура (через AsyncLocal). Он захватывается при await, Tas… Senior6 мин
- 25 Как объект устроен в памяти: заголовок, MethodTable, выравнивание, размер объектов и массивов? Каждый объект ссылочного типа в куче (64-бит) имеет накладные расходы 16 байт: object header (8 байт: sync block index, хэш-код, биты GC и блокировок) и указатель на Met… Senior7 мин