
Комментарии 20
В тему будет книга Mohammad Rahman "C# deconstructed"
Все, чем орудует CLR во время проекта, связанное с неуправляемой средой,
помещается в неуправляемую кучку (англ.unmanaged heap). А именно:
Ресурсы, выделяемые вне полномочий CLR (
Marshal.AllocHGlobal);Дескрипторы (спец. указатели);
Объекты с ручным управлением (производные
IDisposable)
Про IDisposable откровенная ложь написана. Похоже на нейробредни.
Ок, тогда как тогда живут IDisposable производные в памяти процесса?
class MyClass : IDisposable
{
public void Dispose()
{
}
}Вот IDisposable-производная. Какое отношение она имеет к неуправляемой куче?
Цитата "Основное использование IDisposable интерфейса заключается в выпуске неуправляемых ресурсов."
Неуправляемые ресурсы это ресурсы к которым CLR не имеет никакого отношения.
Основное использование IDisposable интерфейса заключается в выпуске неуправляемых ресурсов
Хорошо, вот ещё пример:
class MyClass : IDisposable
{
private readonly CancellationTokenSource _cts = new();
public void Dispose()
{
_cts.Dispose();
}
}По-вашему, `CancellationTokenSource` является неуправляемым ресурсом?
Хорошо, я исправился. IDisposable не игнорируются сборщиком мусора.
Это тоже не так :) Сборщик мусора ничего про интерфейс не знает: если пользователь IDisposable явно не вызовет Dispose (using считается) ничего не произойдёт.
IDisposable - это такой механизм кооперативного детерминированного освобождения ресурсов.
И да, как подсказывают выше, необязательно неуправляемых. Тут Microsoft несколько вводит в заблуждение в своей собственной документации.
Небольшие замечания:
Свойства и в особенности автоматические свойства тоже резко изменяются во время компиляции.
<...>
Мало того, сам
_backingField- это что-то от Roslyn. (я полагаю так).
Поле называется <Count>k__BackingField - да, вместе со скобками. Это невалидное имя в C# - чтобы случайно не получить конфликт с пользовательским кодом - но вполне себе нормальное в CLR.
Когда вы используете
IDisposable-производные,они не находятся в неуправляемой куче. Тем не менее, вы вынуждены явно указывать область жизни таких классов.
Не совсем. Во-первых, .NET не мешает забыть вызвать Dispose, но в большинстве случаев это будет ошибкой, иногда незначительной (ресурс освободится, просто в какое-то непонятное время потом), иногда критической (будет течь память).
Во-вторых, есть ситуации, когда вызывать Dispose не надо. Например, если класс получает IDisposable (типа scoped DbContext) извне как зависимость.
Во-вторых, есть ситуации, когда вызывать
Disposeне надо. Например, если класс получаетIDisposable(типа scopedDbContext) извне как зависимость.
Я хотел сразу возразить, и сказать, что это плохая архитектура, но возможно я не так понял. Можете написать короткий пример c ClassA и ClassB?
DI контейнер это сделает за вас
Если вы получаете IDisposable зависимость в конструкторе:
Пример
class ClassA : IDisposable { ... }
class ClassB : IDisposable
{
private readonly ClassA _a;
private readonly HeavyResource _resource;
public ClassB(ClassA a)
{
_a = a;
_resource = new();
}
public Dispose()
{
_resource.Dispose(); // хорошо
_a.Dispose(); // хорошо. Или плохо?
}
}
class ClassC(ClassA a)
{
public void DoTheThing()
{
using (var b = new ClassB(a))
{
// ...
}
// если ClassA был зарегистрирован в DI как AddScoped<ClassA>(),
// экземпляр больше не юзабелен
a.DoTheThing(); // ObjectDisposedException
}
}бывают случаи, когда диспоузить её будет ошибкой. Например, у ClassA время жизни - скоуп, а ClassB предполалось использовать как короткоживущий объект.
Вы можете подумать: "Да ну, это ерунда какая-то" - ну, возможно будете правы. Идея в том, что, например, в отличие от Rust, в C# непонятно, когда объекты временно заимствуются (и чистить не надо), а когда передаются во владение со всеми соответствующими заботами (и чистить надо). Каждый выкручивается как может, вот у Microsoft самих полно примеров:
public HttpClient(HttpMessageHandler handler, bool disposeHandler);или
public StreamReader(Stream stream, ..., bool leaveOpen = false);очень странная статья, понятно что это ИИ, но как-будто какой-то устаревший, из 2023 - смесь бесполезных фактов + откровенно неверных утверждений, аля
С выходом .NET 7.0 подход изменился. Появилось понятие R2R и Native AOT.
или
И все. Их только четыре. Больше не нужно.
наверное неверных утверждений еще больше, я вскольз глянул
Начиная с .net 7.0 - из экспериментального статуса вышла Native AOT для SCD приложений. Это ИИ?
"Появилось понятие R2R"
"NET application startup time and latency can be improved by compiling your application assemblies as ReadyToRun (R2R) format. R2R is a form of ahead-of-time (AOT) compilation"
Имею право полагать, что до выхода Native AOT, возможности -p:PublishReadyToRun=true не было
Имею право полагать, что до выхода Native AOT, возможности -p:PublishReadyToRun=true не было
Нет, не имеете. R2R был с самых первых версий .NET Core, до этого с нулевых (по-моему с .NET 2.0 или даже 1.1) был NGen - +/- тоже самое (чуть с другой философией, fragile). Какое-то время .NET Core даже поддерживал оба режиме - NGen и R2R.
Уважаемые интересующиеся... Лучше пишите, что это я виноват и чего-то не понимаю, чем сваливать всё на AI-slop. В выводе специально написано, что это моих рук дело. И я за слова в ответе
Не даром я сюда затесался
Забавно, вы похоже не нашли подходящего синонима и вставляете выражения"безопасный/небезопасный" .
На самом деле это старый добрый managed/unmanaged код. .Net как бы вам говорит: не суй клешни куда не просят, но если очень хочется...
С течением времени EF все больше отделяет нас от необходимости долго разбираться с управляемыми и неуправляемыми ресурсами чтобы самостоятельно контролировать их жизненный цицикл.
Тем мне и нравится .Net - все больше и больше он снимает нужду переусложнять код всякими алгоритмами, сложной архитектурой и прочей головной болью которой любят мучить на интервью
.NET под микроскопом | процессы, метаданные, AOT и GC