У меня есть ощущение, что и вы, и xSVPx выше, прочитали мой комментарий так, будто я говорю про превращение в менеджера как о чём-то замечательном. Ну для кого-то - может быть. А я с вами в одной лодке так-то.
Инженеру что, интереснее не дело делать, а исправлять кое-как написанный чатботом код ?
А он и не исправляет. Это делает тот же самый чатбот с новым промптом. Инженер становится менеджером, раздающим команды и нажимающим кнопку Allow.
Получается быстрее и лучше, чем попытки использовать то, что нагенерили вайбкодеры
А представьте, что не только код генерируется, но и бизнес-требования, и таски в джире, причем зачастую самими разработчиками вместо продакт менеджеров, и тем самым размываются роли и обязанности. Мне вот представлять не нужно :(
Задача подготовки декларации для DllImport типовая, и материалов касательно P/Invoke триллионы гигабайтов. К чему это я? Да к тому, что это тот случай, когда можно довериться ИИ-ассистентам.
Что если скрыть использование ОС-специфичных функций за нашим собственным фасадом, предоставив унифицированный API для использования в .NET-коде? Встречайте — нативный бэкенд.
Я бы пошёл путём вроде того, как сделано в dotnet/runtime:
Тем не менее, аргумент остается. Вайб-кодинг (простите, это же теперь оскорбительный термин) ✨агентная инженерия✨, хоть со спеками, хоть без них, должна вам давать невероятное преимущество (10х) перед остальными разработчиками. А есть результаты? Я, может, не туда смотрю (ну вот, например, внимательно читаю Hacker News), но все, что я вижу, это как сделали очередной клон OpenClaw или 114-й по счёту конвертер MCP в CLI. ИИ-тулзы для ИИ. ИИ-тулзы для ИИ-тулзов. ИИ-улучшаторы для ИИ-тулзов. Вывернули все наизнанку: не решения ищем для проблем, а проблемы для решений.
Если вы получаете 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);
Это тоже не так :) Сборщик мусора ничего про интерфейс не знает: если пользователь IDisposable явно не вызовет Dispose (using считается) ничего не произойдёт.
IDisposable - это такой механизм кооперативного детерминированного освобождения ресурсов.
И да, как подсказывают выше, необязательно неуправляемых. Тут Microsoft несколько вводит в заблуждение в своей собственной документации.
Свойства и в особенности автоматические свойства тоже резко изменяются во время компиляции.
<...>
Мало того, сам _backingField - это что-то от Roslyn. (я полагаю так).
Поле называется <Count>k__BackingField - да, вместе со скобками. Это невалидное имя в C# - чтобы случайно не получить конфликт с пользовательским кодом - но вполне себе нормальное в CLR.
Когда вы используете IDisposable-производные,они не находятся в неуправляемой куче. Тем не менее, вы вынуждены явно указывать область жизни таких классов.
Не совсем. Во-первых, .NET не мешает забыть вызвать Dispose, но в большинстве случаев это будет ошибкой, иногда незначительной (ресурс освободится, просто в какое-то непонятное время потом), иногда критической (будет течь память).
Во-вторых, есть ситуации, когда вызыватьDisposeне надо. Например, если класс получает IDisposable (типа scoped DbContext) извне как зависимость.
Странный спор у вас тут происходит, но ваша собственная ссылка различает elvis (a ?: b) и тернарный (a ? b : c) операторы. У них же даже арность разная, как они могут быть одним и тем же.
А если говорить про C#, у нас под elvis'ом всегда понимался null-conditional operator (?.), а тернарный всегда был тернарным.
Не знаю. Не хочу умалять ваш труд, но я тоже не вижу для себя применение этой штуки. Чем старше я становлюсь, тем больше ценю подходы потупее и попроще.
Надо подружить два класса - можно повесить internal и положить в отдельную сборку (хотелось бы в дотнете модулей поменьше, как в Rust, ну да ладно). Либо через explicit interface implementation, чтобы методы или свойства не отсвечивали в intellisense. Либо скрыть через EditorBrowsable(Never). Либо как в EF Core - положить в Internal namespace и написать анализатор. Влезть можно - но на свой страх и риск. В конце концов, знак "Осторожно! Злая собака" не призван запретить вам перелезать через забор, только лишний раз подумать ;)
Большой плюс подходов выше - они простые, используются много лет и всем знакомы. Если разработчик увидит EditorBrowsable(Never) - он поймёт что это такое и для чего.
Большой минус OnlyYou<T> - сложность её понимания превосходит пользу, которую она приносит. Имхо, конечно.
ПС. Поставил вам плюсик за готовность воспринимать критику. Эта статья читается намного проще.
Несколько лет назад я бы сам ворчал, дескать, JSON - текстовый формат, расточительно, неэффективно, бу-бу-бу. Сейчас у нас есть парсеры, ворочающие JSONы гигабайтами в секунду.
Вы никак не отнимите у JSON его огромный плюс - он поддерживается практически любым языком программирования, можно читать даже на тостере или утюге. Так уж сложилось. Поздно брюзжать про бинарные СТАНДАРТНЫЕ форматы.
У меня есть ощущение, что и вы, и xSVPx выше, прочитали мой комментарий так, будто я говорю про превращение в менеджера как о чём-то замечательном. Ну для кого-то - может быть. А я с вами в одной лодке так-то.
А он и не исправляет. Это делает тот же самый чатбот с новым промптом. Инженер становится менеджером, раздающим команды и нажимающим кнопку Allow.
А представьте, что не только код генерируется, но и бизнес-требования, и таски в джире, причем зачастую самими разработчиками вместо продакт менеджеров, и тем самым размываются роли и обязанности. Мне вот представлять не нужно :(
У меня аж олдскулы свело! Нашёл где можно покликать :) https://flasharch.com/en/archive?q=BitMagic+Corporation&sT=4
Ещё есть https://github.com/microsoft/CsWin32
Я бы пошёл путём вроде того, как сделано в dotnet/runtime:
один класс, но разная имлементация в смежных файлах, например ConsolePal.Windows.cs, ConsolePal.Unix.cs
условный Compile в зависимости от ОС: windows, unix (glob'ы чтобы не прописывать каждый файл, тоже должны работать)
Я бы спускался в unmanaged разве чтобы обернуть в
extern "C"какую-нибудь безнадёжно C++'вую библиотеку.Ну не сами байты, конечно, а вот логи (во сколько подключились, куда, сколько байт загрузили за сессию и т.д.) и сливают, и хранят.
Ну байтов же поток, вот он и льется. :shrug:
И Luau
Тем не менее, аргумент остается.
Вайб-кодинг(простите, это же теперь оскорбительный термин) ✨агентная инженерия✨, хоть со спеками, хоть без них, должна вам давать невероятное преимущество (10х) перед остальными разработчиками. А есть результаты? Я, может, не туда смотрю (ну вот, например, внимательно читаю Hacker News), но все, что я вижу, это как сделали очередной клон OpenClaw или 114-й по счёту конвертер MCP в CLI. ИИ-тулзы для ИИ. ИИ-тулзы для ИИ-тулзов. ИИ-улучшаторы для ИИ-тулзов. Вывернули все наизнанку: не решения ищем для проблем, а проблемы для решений.Обычно хватает взгляда на заглавную картинку. Если на ней нейрослоп, не несущий никакого смысла, то статью можно сразу в мусорку.
Если вы получаете
IDisposableзависимость в конструкторе:Пример
бывают случаи, когда диспоузить её будет ошибкой. Например, у
ClassAвремя жизни - скоуп, аClassBпредполалось использовать как короткоживущий объект.Вы можете подумать: "Да ну, это ерунда какая-то" - ну, возможно будете правы. Идея в том, что, например, в отличие от Rust, в C# непонятно, когда объекты временно заимствуются (и чистить не надо), а когда передаются во владение со всеми соответствующими заботами (и чистить надо). Каждый выкручивается как может, вот у Microsoft самих полно примеров:
или
Это тоже не так :) Сборщик мусора ничего про интерфейс не знает: если пользователь
IDisposableявно не вызоветDispose(usingсчитается) ничего не произойдёт.IDisposable- это такой механизм кооперативного детерминированного освобождения ресурсов.И да, как подсказывают выше, необязательно неуправляемых. Тут Microsoft несколько вводит в заблуждение в своей собственной документации.
Небольшие замечания:
Поле называется
<Count>k__BackingField- да, вместе со скобками. Это невалидное имя в C# - чтобы случайно не получить конфликт с пользовательским кодом - но вполне себе нормальное в CLR.Не совсем. Во-первых, .NET не мешает забыть вызвать
Dispose, но в большинстве случаев это будет ошибкой, иногда незначительной (ресурс освободится, просто в какое-то непонятное время потом), иногда критической (будет течь память).Во-вторых, есть ситуации, когда вызывать
Disposeне надо. Например, если класс получаетIDisposable(типа scopedDbContext) извне как зависимость.Странный спор у вас тут происходит, но ваша собственная ссылка различает elvis (
a ?: b) и тернарный (a ? b : c) операторы. У них же даже арность разная, как они могут быть одним и тем же.А если говорить про C#, у нас под elvis'ом всегда понимался null-conditional operator (
?.), а тернарный всегда был тернарным.Не знаю. Не хочу умалять ваш труд, но я тоже не вижу для себя применение этой штуки. Чем старше я становлюсь, тем больше ценю подходы потупее и попроще.
Надо подружить два класса - можно повесить
internalи положить в отдельную сборку (хотелось бы в дотнете модулей поменьше, как в Rust, ну да ладно). Либо через explicit interface implementation, чтобы методы или свойства не отсвечивали в intellisense. Либо скрыть черезEditorBrowsable(Never). Либо как в EF Core - положить вInternalnamespace и написать анализатор. Влезть можно - но на свой страх и риск. В конце концов, знак "Осторожно! Злая собака" не призван запретить вам перелезать через забор, только лишний раз подумать ;)Большой плюс подходов выше - они простые, используются много лет и всем знакомы. Если разработчик увидит
EditorBrowsable(Never)- он поймёт что это такое и для чего.Большой минус
OnlyYou<T>- сложность её понимания превосходит пользу, которую она приносит. Имхо, конечно.ПС. Поставил вам плюсик за готовность воспринимать критику. Эта статья читается намного проще.
Почему?
А. Ну я на стадии принятия :)
А что не так с pwsh?
Да тут у многих беда с хабами.
Упомянули интернет - фигачим хаб дотнета! А что, .NET, интернет - да какая разница, похоже же.
Или человек бухтит про что-то своё жизненное, упоминает как 10 лет назад юзал EntityFramework - всё, пихаем в хаб с сишарпом!
/me вздыхает
Вы правы :)
Очевидно, что JSON - good enough, он не идеален и подходит не во всех ситуациях.
Несколько лет назад я бы сам ворчал, дескать, JSON - текстовый формат, расточительно, неэффективно, бу-бу-бу. Сейчас у нас есть парсеры, ворочающие JSONы гигабайтами в секунду.
Вы никак не отнимите у JSON его огромный плюс - он поддерживается практически любым языком программирования, можно читать даже на тостере или утюге. Так уж сложилось. Поздно брюзжать про бинарные СТАНДАРТНЫЕ форматы.