Pull to refresh
13
0.5
Send message

Если вы получаете 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> - сложность её понимания превосходит пользу, которую она приносит. Имхо, конечно.

ПС. Поставил вам плюсик за готовность воспринимать критику. Эта статья читается намного проще.

А. Ну я на стадии принятия :)

А что не так с pwsh?

Да тут у многих беда с хабами.

Упомянули интернет - фигачим хаб дотнета! А что, .NET, интернет - да какая разница, похоже же.

Или человек бухтит про что-то своё жизненное, упоминает как 10 лет назад юзал EntityFramework - всё, пихаем в хаб с сишарпом!

Очевидно, что JSON - good enough, он не идеален и подходит не во всех ситуациях.

Несколько лет назад я бы сам ворчал, дескать, JSON - текстовый формат, расточительно, неэффективно, бу-бу-бу. Сейчас у нас есть парсеры, ворочающие JSONы гигабайтами в секунду.

Вы никак не отнимите у JSON его огромный плюс - он поддерживается практически любым языком программирования, можно читать даже на тостере или утюге. Так уж сложилось. Поздно брюзжать про бинарные СТАНДАРТНЫЕ форматы.

Вот бы человечество придумало что-то вроде анализатора, который бы находил неиспользуемый код в библиотеках (и в пользовательском коде тоже можно, кстати) и удалял из скомпилированного артефакта. Можно даже придумать какое-нибудь прикольное название, например, tree shaking. Тогда не станет проблемы +10 Мб, а библиотеки останутся полезными.

Приехали вот сегодня в мои края :)

У меня ощущение, что где-то заканчивается онлайн-курс по ИИ и всем выдали финальную домашку навайбкодить продукт и написать статью на хабр о том, как добиться успешного успеха, обязательно с выводами и горсткой советов.

А вот когда люди поймут, что те, кто продвигал Open Source, тупо отдали благосостояние всей индустрии капиталистам

Можно подумать, отсутствие открытого кода остановило бы ИИ-компании. Авторы 500 тысяч книжек кому что отдали? "Капиталистам" это просто стоило 1,5 миллиарда президентов США - дороговато, но никто даже за решётку не сел.

Хммм. Я полез разбираться, оказывается, чтобы на винде в Edge тоже заработало, странице нужно явно проставлять метаданные через Media Session API. После этого работает пауза, хотя трек надо включать вручную:

navigator.mediaSession.metadata = new MediaMetadata({
  title: 'DevOpsRadio',
  artist: 'boombick',
});

Трек начинает ставиться на паузу/воспроизводиться по ⏯️, но страница не понимает, что что-то произошло:

Всё ещё играем? Или уже нет?
Всё ещё играем? Или уже нет?

Можно добавить обработчики...

  navigator.mediaSession.setActionHandler("play", () => radioPlayer.play());

  navigator.mediaSession.setActionHandler("pause", () => radioPlayer.stop());

но при остановке трека кнопки снова перестают работать. Gemini говорит, вот это

this.mainAudio = null;

прибивает медиа сессию и советует вместо зануления mainAudio прибивать src:

// Inside stop()...
this.mainAudio.removeAttribute('src'); // Better than src = ''
this.mainAudio.load(); // Forces the browser to drop the network connection

// Inside play()...
this.mainAudio.src = '/radio/stream'; // Re-assign the stream

@boombick не посмотрите? 🙏

А у меня тоже вопрос в догонку к предложениям выше :)

Можно ли привязать медиа-клавиши к странице? То есть чтобы по клавишам Play/Pause на клавиатуре можно было включать/ставить на паузу, например, как это происходит с вкладками YouTube.

Никто не мешает. В том числе никто не мешает ИИ-агентам смотреть ваш код и безвозмездно обучаться на нём. Читайте новости в оригинале:

the team over at Gentoo has made a decision: they'd rather not have Copilot on GitHub going through all of their code.

интервьюерам придётся выдумывать ещё более изощрённые вопросы и способы детектировать "пассажиров" на собеседованиях

Забьют на онлайн-собеседования. Или будут просить включить вторую камеру, которая бы смотрела в монитор

1
23 ...

Information

Rating
2,297-th
Registered
Activity