Комментарии 13
Сильно не разбирался, но, нюхом чую какой-то велосипед. :)
Вместо:
Func<List<object>, CancellationToken, Task> taskDelegate = ....
в наше время лучше уже писать:
static Task taskDelegate(List<object> events, CancellationToken cancellationToken)
{
....
}
Со вторым делегатом точно так же. Это называется "local functions".
А вот это:
catch (Exception ex)
{
....
throw new Exception("...");
}
так вообще только джуну простительно - innerException
передавать-таки надо.
Вы на предупреждения и подсказки вообще не смотрите? Насколько я знаю, про такие вещи даже "голая" IDE без всяких спецнастроек говорит.
Да и вообще базовый эксепшен выкидывать это моветон. О чем там даже варнинг должен быть от рослина. Тут прям академический пример как не надо делать: максимально безликий эксепшен и похереный стек трейс) Или в иннер завернуть, или голый throw; но не так.
Но тут явно проигнорированы все усилия команды майкрософта) Проверка аргумента в конструкторе на налл - для чего? DI контейнер все равно раньше эксепшен выбросит если сервис в контейнере не найдет. Это мертвый код. К дизайну тоже есть претензии, а List<object> вызывает просто скрежет зубовный, ну не фреймворк же 2.0 на дворе. А если б был, ну хоть бы ArrayList тогда. Ну да ладно, все равно велосипед.
Спасибо за интерес к моей публикации! Давайте разберемся подробнее:
1) Выброс исключения в приведенном примере имеет исключительно поведенческое назначение и осуществляется в "пользовательском коде". Он может быть описан на усмотрение разработчика как угодно, более того, его содержимое в данном случае абсолютно никак не влияет на дальнейшее поведение. У меня VS 2022 PRO v. 17.13.4 с конфигурацией Roslyn по умолчанию и подсказок по этому поводу нет / странно, правда?
2) Спасибо за замечание по поводу выброса исключения при внедрении DI. На самом деле, это базовая защита от ошибок со стороны разработчиков:
- Явное указание на зависимость: Проверка на null
явно показывает, что внедряемая зависимость является обязательной для работы класса. Это улучшает читаемость кода и помогает другим разработчикам понять, какие зависимости необходимы для правильной работы класса.
- Предотвращение скрытых ошибок конфигурации DI-контейнера: DI-контейнеры обычно настроены таким образом, чтобы выбрасывать исключение, если не удается разрешить зависимость. Но в некоторых случаях (например, при неправильной конфигурации или при использовании fallback-механизмов) контейнер может внедрить null
вместо ожидаемой зависимости. Проверка на null
в конструкторе служит дополнительной защитой от таких ситуаций.
- Разработчик может передать null по ошибке, об этом можно прочитать здесь stackoverflow.com/a/72727192/11716490
3) В решении используется List<T>
, что обеспечивает безопасность типов, то есть Вы случайно не добавите string
к int
, object
лишь обобщённый пример, лучше было бы указать T
?
Разумеется дженерик лучше. По целой куче причин, от контроля типов до производительности.
Вы приводите пример в котором явным образом выброс исключения нарушает все возможные бест практисез по выбросу исключений. Я не могу сказать про конкретные версии студии, и дефолтные настройки, но последние анализаторы рослина ругаются на выброс базового эксепшена точно, а любой дополнительный тул в виде решарпера, или сонаркуба, дополнит про потерянный стек трейс. Не давайте плохих примеров - это мой поинт. Если эксепшен не важен - не бросайте. Если это плейсхолдер - напишите это через коммент // Here is the placeholder for exception handling. И тд. Не давайте плохой код в качестве примера. Разработчик не может по ошибке передать налл в объект, который он не создает, поэтому этот код - мертвый в релизе. Не пишите мертвый для релиза код в проектах, и тем более в примерах, где этот код не важен. Не говоря о том, что ребята из МС озаботились созданием хэлперов и аттрибутов для описания и валидации параметров, и ваш код выглядит по-школьному даже если предположить что эта проверка там нужна. Тогда параметр надо объявить как наллабл, пометить аттрибутом для анализаторов и было бы хорошо воспользоваться хэлпером ArgumentNullException.ThrowIfNull(...); чтобы было по-взрослому.
Не нужно для примера, не важно в контексте - не пишите! Это рекомендация.
Вы заметили много проблем в коде автора, но сейчас вы сами приводите вредный совет. Если параметр объявлен как nullable то как раз таки метод должен мочь с этим null корректно работать. И кидать ArgumentNullException в этом случае не надо. Наоборот, в случае not nullable параметра туда все равно могут передать null, и проверка на null нужна. То что это DI-конструктор еще не означает что его никто не сможет вызвать без DI.
Огромное спасибо за интерес к моей публикации! Давайте разберемся подробнее:
1) Статические функции (методы) в C# не могут содержать ссылки на объекты экземпляра (non-static). Это фундаментальное ограничение, зачем Вы предлагаете осознанно вводить его? Мне такой вариант не подходит.
2) Спасибо за замечание по поводу innerException
. Выброс исключения в приведенном примере имеет исключительно поведенческое назначение и осуществляется в "пользовательском коде". Он может быть описан на усмотрение разработчика как угодно, более того, его содержимое в данном случае абсолютно никак не влияет на дальнейшее поведение. По поводу выброса с включением innerException в самом решении, у меня VS 2022 PRO v. 17.13.4 с конфигурацией Roslyn по умолчанию, подсказок по этому поводу нет / странно, правда?
Описание довольно сумбурное, понять автора довольно сложно. А почему надо что-то откладывать, дополнительно консолидировать и т.п.? Нельзя ли просто на входные параметры ключ уникальный сделать, один раз по ним отработать и результат по ключу закэшировать? Если надо распределить нагрузку, то можно на входе очередь поставить, а если параметры пухлые и хранить их дублями неэффективно, то дедупликацию можно и на основе очереди сделать, к примеру, Kafka это из коробки умеет.
Здравствуйте, спасибо за Ваши вопросы по моей публикации!
Отложенное выполнение -> чтобы не занимать время выполнения основной операции. Совсем не хочется применять Fire-and-forget на огромное количество операций.
Поэтому, чтобы не отправлять из каждой инстанции тысячи мелких запросов, консолидированные данные конкатенируются в один объект и отправляются одним запросом (что по итогу вышло быстрее как со стороны отправителя, так и потребителя).
Kafka я рассматривал в качестве решения, но мне хотелось снизить до минимума нагрузку на самописный брокер, поэтому дедупликация в том числе на стороне клиента, ведь масштабирование WebSocket'ов имеет некоторые общеизвестные ограничения https://learn.microsoft.com/en-us/aspnet/core/signalr/scale?view=aspnetcore-8.0.
Возможно, я ошибаюсь, или не так Вас понял? Вообще, у этого решения может быть много других сценариев использования, помимо вышеописанных.
Вообще ничего не понял. Какая основная операция? Что это такое вообще?
Вы так все и в статье, и в комментариях объясняете, как будто все уже здесь понимают, что у вас за система и какие проблемы она решает. Нет. Вообще ничего непонятно. В статье набор кусков кода, которые между собой никак не связаны. Да и сам по себе код плохо читаемый, заглянул в Git - там тот же винегрет, только его больше.
Стилистика ужасная, взять те же определения Func<List<object>, CancellationToken, Task> в коде методов - кошмар. За собачки в именах переменных тоже плюс не поставлю, но это ладно.
Как вообще из статьи понять, что дедупликация на стороне КЛИЕНТА? Здесь он не упоминается от слова совсем, ну и кода клиента, конечно же, нет.
Вообще, у этого решения может быть много других сценариев использования, помимо вышеописанных.
Каких сценариев? Здесь что-то малопонятное (опять) написано в разделе "Альтернативные варианты", но и все. вся статья - жуткая каша.
На закуску: вы тут пишете про какой-то делегат TaskFactory, который содержит кастомную логику. Кастомную логику для чего? Тут он какие-то задачи создает, но в примере он создает задачи-пустышки, ни с чем не связанные. Что они вообще должны делать и на основе чего (что на входе)? Если есть кастомная логика, то должна быть и дефолтная логика. Если она есть, то где она здесь? Зачем для делегата использовать название, которое подходит классу, кстати, во фреймворке есть класс с таким названием, и это один из базовых классов TPL, я бы не стал его название для чего-то другого использовать.
Да, действительно какая-то ерунда, согласен с предыдущими комментариями. Думаю, классический пример разработчика, который выучил паттерны и термины, пытается следовать инструкциям, но вряд ли понимает, что на самом деле происходит. На самом деле, такое очень распространено, почти все так и кодят.
Было больно читать как текст так и код. В дотнете уже есть готовый механизм на ченелах и куча других очередей.
Событийный диспетчер отложенных задач на C#: консолидация и дедупликация данных в текущей инстанции