10 худших моментов языка C#, которые прочувствуют только профи

preview_player
Показать описание
#DevJungles #dotnet #csharp

Поддержать канал можно:
- Спонсорством на YouTube
- Переводом на карту или пополнением банки монобанка:
Dev Jungles YouTube Channel Fund

Номер карты банки:
5375 4112 0230 1466

- Или криптой:
Binance Id: 479881646

BTC - 18C3jsFYwviN5FvzpAt4uMWRfUeVKvdWxy
ETH - 0x2903f63ba9009732272e91a299053b9d7b623216

USDT on ERC20 - 0x2903f63ba9009732272e91a299053b9d7b623216
USDT on TRC20 - TSmS5RzQKbWdxZkoM2oRo9HK8FYBaq744T

LTC - LN3CkrnvZLZTXDUhqTy1gUKMVpLjEPA4G2

DOGE - DPwon439jf3axVSBwyuXso6z7CivuJF655
AAVE - 0x2903f63ba9009732272e91a299053b9d7b623216
Waves - 3P8D57Zw7CrqW2o7dHpvZR2UzAzQRFA2kZd

Наш родной С# почти всегда прекрасен и вытягивал нас из разных переплетов.
Но и он не свят и в нем есть недостатки.
Есть те, разговоры о которых уже набили всем оскомину: как то, например то, что все по умолчанию изменяемо и нужно делать дополнительные манипуляции, что бы сделать объект immutable, хотя работа в эту сторону идет(те же record).
Или еще много было сказано, про старый синтаксис делегатов. Он и правда ужасен, но давайте по-честному: вы когда его последний раз видели?

Сегодня я хочу обстоятельно поговорить о том, что регулярно отстреливает нам на реальных проектах! Что делает их сложнее там, где этого можно и нужно было бы избежать. Но скажу не только о проблемах, но и предложу для них решения, а еще накидаю контекста почему так было сделано, потому погнали!

Сегодня:
record struct внезапно оказались mutable!
event subscribtion/unsubscribtion просто ужасны!
default parameters отстреливают в ногу каждому второму!
Нужно перевернуть половину проекта, когда передаешь параметры в base constructor
И многое другое!

Тайм-коды:
00:00 - Вступление
02:30 - 10 место
04:50 - 9 место
10:00 - 8 место
13:17 - 7 место
17:12 - 6 место
19:50 - 5 место
21:36 - 4 место
24:59 - 3 место
27:56 - 2 место
31:08 - Достойны упоминания
34:59 - 1 место
37:49 - Вывод
Рекомендации по теме
Комментарии
Автор

Чел, хорош, контент вообще в кайф!! Можно вот этого вот всего почаще❤❤❤

rogiawos
Автор

Замечательное видео)
Внесу свою лепту (как человек что много лет пишет на чистом С/Ассемблере, а сейчас пишу этот комеет как С# фулстек)

1) модификаторы доступа - это годнота. Если не нужно, то не используешь "лишнее". У С\C++ вместо internal вообще static (это при том, что там есть external)
Я выступаю за то, чтобы был максимально гибкий контроль за областью видимости, потому как много раз видел, как сужение области видимости просто "схлопывает" тонны кода на выхлопе компилятора. И таких инструментов, которые несут смысл как для программиста, так и для компилятора очень мало, если так подумать

2) Мне очень нравится, что вложенные типы видят приватные поля тех, что выше по иерархии. Благодаря этому можно очень красиво делать реализации Строителей.
Если делать как по науке, то нужно подводить желаемый тип под интерфейс, в котором можно менять значения полей. И сам интерфейс хорошо бы спрятать, чтобы уши не торчали... а так, вложил один тип в другой и всё готово. Потому как руки всё равно потянтся проверить, а не будет ли у типа фабричного метода, если конструктор приватный
Про путаницу с модификаторами доступа по умолчанию -- полностью солидарен

3) Дженерики - это прям беда. Столько раз себя ловил на мысли, что это какой-то кастрат плюсовых шаблонов, что аж неловко становилось
Они ну слишком базовые. Есть попытки в метапрограммирование (те же where и всякие контр/ко/ин-вариантности), но пользоваться ими очень неудобно, когда нужно работать с иерархией этих типов
Спасаемся базовыми типами, как и было упомянуто в видео)

Но лично моя боль №1 -- поведение структуры с интерфейсами
Это прямо дичь. Моментально рушится вся идея строго значимого типа. Плюс к тому очень много странных ограничений (нельзя давать полям значения по умолчанию, вне конструктора без аргументов, но как только ты этот самый конструктор определяешь, то ты рушишь целую вереницу оптимизаций, что заботливо для тебя выстроили авторы языка)
А те же readonly ref struct я смог применть только в паттерне итератор. И работает это только из-за костылей с утиной типизацией... вне этого как только у тебя появляется хоть маломальски выстроенная иерархия типов и ты хочешь внести "перформанса", то ты быстро обнаруживаешь, насколько же у тебя связаны руки. Либо рефлексия, либо переписывать всё в совсем другой парадигме
Я бы добавил интерфейсу гарантию, что он представляет только значимый тип (с синтаксисом для такого поведения).
По сути легальный и чистый способ для утиной типизации

С# получился очень удобным прикладным языком
И он может решать целый спектр задач
Потому его сейчас как лебедь/рак/щука тянут в сторону обратной совместимости, рядом новые и модные практики с функциональщиной, а особняком системные программисты, которым нужон High Performance

Ещё раз выражаю благодарность за видео и труд!
Смотрю тебя с большим удовольствием)

MrNachosVIDEOS
Автор

Невероятно интересный видос. Большое тебе спасибо ❤

helx
Автор

Мне пришлось перейти с C# на Java, ребят. Как же вы счастливы, ребят, вы не понимаете, насколько C# кажется прекрасным после перехода на джаву!

jdkxnbt
Автор

Хаха, я смог заполнить switch expression. Буквально всего то пара лет прошло) Теперь осталось запомнить синтаксис его паттерн матчингов.

ppc
Автор

очень хорошее видео, благодарю за труд

redice
Автор

Не знал о некоторых проблемах даже, повезло-повезло.
Спасибо, интересный формат!

zddimqz
Автор

Крутое видео. Спасибо за воркэраунды для некоторых проблем!

qpbtgqb
Автор

Ух, про switch прямо в точку. Помню сходил на неделю в отпуск и напрочь забыл его синтаксис. Дело было года два назад, когда он только входил в обиход.
По части модификаторов доступа - там еще file завезли) а где internal, там и InternalsVisibleTo, так сказать)

P.S. На фразе «С деструктором все еще хуже. Во-первых, он у нас… есть» заржал и подавился своим смузи

gnchrtd
Автор

Спасибо за очередное полезное!) Никак не пойму как до такого уровня подняться. Ты не рассказывал про свой путь, что надо сделать? Не поступать в вуз, сразу стартапы, куча пет проектов и потом куча ком. проектов, не жениться (чтобы не отвлекали), с друзьями никуда не ходит и пр. Поделись лайф хаком, очень интересно!)

grant
Автор

я десь рік тому стикнувся з 10-ю проблемою, тоді теж мало не здурів і майже постарів на 50 років поки дебажив, в кінці в мені щось перегоріло і я просто змирився що це так не працює, розбиратись в причинах вже не було ні часу ні моральних сил, просто переробив і забув.
Ти зараз прям витяг на "світ божий" коварне зло приховане в пітьмі, яке паскудить життя багатьом.
Вважай - ти рятуєш людям нерви і час для чогось більш прекрасного, так тримати👍

independentexpert
Автор

У меня как-то было веселье с перегрузкой методов. Уже не помню деталей, но идея была в том что было 2 версии метода и одна принимала энум, а вторая инт. В итоге я передаю энум, а вызывается версия с интом.

denys-p
Автор

Дуже дякую. Корисне відео. Реквест на налаштування статичних аналізаторів. Тільки в студії, а не в цих ваших джетбрейнах!

HOSTRASOKYRA
Автор

Добротний відос. Тепер по пунктах
10) Все правильно, так влаштовані інтерфейси - я не хочу знати внутрішню імплементацію (вона взагалі може бути в іншій інтернал френдлі ассемблі, або замокана в тестах), а працювати лише з публічним контрактом, тому x і має бути 10
9) Теж логічно, але неочевидно - лише на досвіді трекаєш таке.
8) void - зло, a async void - ще більше зло :)
7) event - в топку, застаріло, краще юзати Rx. Конкатенація делегатів може бути корисною в маппері, наприклад, коли накидуєш на маппінг одного проперті декілька делегатів
5) Type inference - це біль C# та аналізаторів синтаксису. F# в цьому плані дуже органічний
4) protected - це біч ООП, коли писали все на Rich Domain Model, де дані та поведінка інкапсулювалися в самому класі і для модифікації функціональності лишалося засабкласитися з оверрайдами (привіт Template Method pattern).
Pubilc модифікатор в інерфейсах юзаю лише тоді, коли далі йде дефолт імплементація - це дозволяє візуально відрізняти вже імплементовані методи від тих, які треба імплементувати в нащадках
2) Конструктор ще не можна передати як посилання на метод, типу .Select(Myobj.ctor) і доводиться писати .Select(_ => new Myobj())
1) Вітаю, ти віднайшов property injection :) В Blazor є відповідний атрибут [Inject], де можна врізати свій сервіс без зміни всіх нащадків

nanvlad
Автор

К обходу 7-й проблемы в пример можно ещё библиотеку System.Reactive привести. Там тоже логика помещения подписки в IDisposable используется. Также есть механизмы адаптации классических событий. Но, с другой стороны, это уже не Subscriber/Puslisher, а Observable/Observer получается.

Ivolution
Автор

Хорошее видео, насчёт конструкторов с абстрактными классами полностью согласен, а так же с асинхронными и не асинхронными перегрузками. Как по мне уже давненько пора отказаться от явного применения Task с асинхронными методами и отдать это на вотчину компилятора, т.к. нам, как правило, нужен дженерик объект таска, а не сам таск, 🤘

vladrega
Автор

Хорошее видео, Новый switch case конечно же это ужас. + в последних версиях шарпа очень много сахара, это не очень радует.!

mudrecsalimkhanov
Автор

На счёт конструкторов: можно сгенерировать пачку паршл классов в которых определяется конструктор. Либо иньектить зависимости в свойства. Ну а 50 тестов всё ровно придётся изменить.

pnrmxrx
Автор

По поводу последней проблемы: в Rider есть удобная функциональность, добавляющая аргументы в функцию, если в одном из мест вызова дописать этот аргумент. Это же применяю и при добавлении нового параметра в базовый класс.
Так же можно через меню рефакторинга это же сделать — в popup окне вписываешь название и типа аргумента, и он появляется во всех наследниках.

Не знаю, как там в VS — давно не использовал

DjonNIK
Автор

У меня проблема, которая на первом месте, была в ts'e, только там в конструкторе было 17 сервисов, в родитель я передавал 10, у того был еще один родитель с 4 параметрами. И к этим четырём параметрам надо было добавить пятый... Энивей у свитч экспрешена первое место у меня

meeygqj