Внимание! Эта статья не является «серьезной аналитикой». Только мои мысли и наблюдения.
Любите наблюдать за развитием дотнета? Вот, и я люблю. В данный момент не существует опубликованного списка изменений для будущих .NET 11 и C# 15, не говоря уж о более поздних версиях. Даже Devblogs пока хранит молчание. Благо, что C# - быстро развивающийся язык, и кое-что мы можем понять даже сейчас, если посмотрим, над чем активно ведется работа, а так же по запрашиваемым сообществом фичам.
Runtime async
Наверное, вы уже слышали о runtime async, даже есть отличная статья на Хабре. Если коротко, это позволит создавать легковесные асинхронные задачи, как горутины в Go, управление которыми ляжет на рантайм, без нагрузки на потоки ОС. Без преувеличения, самая ожидаемая фича, которая позволит C# выбить главный козырь из рукава Go.
UPD. @Lewigh верно подметил, что в статье говорится о несколько ином подходе:
Для реализации Async2 были рассмотрены два подхода: размотка стека (tasklets, stack unwindind) и JIT-сгенерированные машины состояний (continuations, JIT State Machine). Подход на основе JIT оказался предпочтительным благодаря лучшей совместимости с текущей инфраструктурой .NET, меньшим накладным расходам и более высокой производительности в большинстве сценариев. Размотка стека, хотя и поддерживает сложные конструкции, такие как byref и span, оказалась менее практичной из-за увеличения времени пауз сборки мусора и сложности реализации.
Самое главное, что всем знакомый синтаксис async\await не поменяется, так что это настоящий must have.
Можете сами ознакомиться с Issue по теме.
Union types
Типы объединений в функциональном стиле стали бы интересной возможностью в C#. Информация о них появилась еще в августе этого года, когда Мадс Торгерсен, ведущий разработчик языка C#, поделился планами об этом в видео.
Мотивация понятна: вы можете описывать типы, которые более дословно соответствуют API (как в TypeScript), например типичное:
{
...
someValue : string | int
}
Теперь можно будет описать новой конструкцией:
public union Union<T1, T2>(T1, T2);
...
Union<string, int> SomeValue;
Обратите внимание, что синтаксис объединений еще может поменяться.
Runtime reflection?
Звучит громко, понимаю. В данный момент рефлексия - самое слабое место C#. При активном развитии AOT и source generators, именно рефлексия вставляет палки в колеса. К счастью, развитие языка показывает, что и это временные трудности. Из недавнего можно вспомнить LibraryImport, UnsafeAccessor, partial events\constructors\properties. А что будет дальше?
Вероятно, нас ждут возможности по типу Enum.Source.Generator, но из коробки. К сожалению, единого мнения пока нет.
Tail return
В C# любая рекурсия (т.е. вызов функцией самой себя) требует O(n) памяти только для стека вызовов, то есть ваш алгоритм не может занимать меньше O(n) памяти. Как быть? Интересное предложение о добавлении нового ключевого слова для описания хвостовой рекурсии появилось аж в 2019 году.
void M(int x)
{
...
tail return M(x - 1);
}
Хвостовая рекурсия - это особый вид рекурсии, при котором последний шаг в функции - это вызов самой себя.
В этом случае результат вызова возвращается сразу, без дополнительных действий.
Преимущества хвостовой рекурсии:
Меньше памяти - такие программы используют меньше места в памяти.
Нет переполнения - это особенно важно, если в программе много рекурсивных вызовов.
Функциональные (и не только) языки активно используют эту фичу, уменьшая накладные расходы на вызов. Надеюсь, C# рано или поздно реализует данную возможность из коробки.
К сожалению, последнее обновление в обсуждении числится началом января этого года.
Комментарии (19)

Lewigh
29.12.2025 08:33Runtime async
Наверное, вы уже слышали о runtime async, даже есть отличная статья на Хабре. Если коротко, это позволит создавать легковесные асинхронные задачи, как горутины в Go, управление которыми ляжет на рантайм, без нагрузки на потоки ОС.
Боюсь Вы не до конца поняли как статью так и механику.
В указанной Вами статье:
Для реализации Async2 были рассмотрены два подхода: размотка стека (tasklets, stack unwindind) и JIT-сгенерированные машины состояний (continuations, JIT State Machine). Подход на основе JIT оказался предпочтительным благодаря лучшей совместимости с текущей инфраструктурой .NET, меньшим накладным расходам и более высокой производительности в большинстве сценариев. Размотка стека, хотя и поддерживает сложные конструкции, такие как byref и span, оказалась менее практичной из-за увеличения времени пауз сборки мусора и сложности реализации.
указано что как раз был выбран путь не как в Go. Если сильно упростить - останеться та жа стейт-машина но создаваться и поддерживаться она будет на уровне рантайма.
Без преувеличения, самая ожидаемая фича, которая позволит C# выбить главный козырь из рукава Go.
Ничего никто выбивать не пытаеться, у .Net итак все очень хорошо и никаких козырей у Go нет. В .Net, JVM и Go у каждого свой подход к решению проблемы, со своими плюсами и минусами.
К примеру для виртуальных потоков Java главная задача была - это безболезненно мигрировать огромное количество проектов. Для Go - создать шайтан машину которое позволит разработчикам вообще не грузить голову по поводу управления задачами в среднем по больнице. Для C# - это - наглядность и управляемость.

iamkisly
29.12.2025 08:33С нетерпением жду статью "Как поменяется .NET и C# в ближайшие годы В РОССИИ ?" потому что пока что весь локальный рынок захватили java и go стеки, и шарп остался какой-то нишевой штукой на грани легаси, где только Dodo и Ozon мейнстримно поддерживают его

Spearton
29.12.2025 08:33В рф в принципе не так уж и много вакансий с НЕ легаси, в сравнении с другими рынками, а всякие сберы и яндексы несут мусорные технологии (например у яндекса это приложения на электроне или другом подобном фреймворке, вместо нормальных кроссплатформенных приложений)

Mikle2024
29.12.2025 08:33Я полный профан в разработке, хоть мне и легко давались практика и теория C# несколько лет назад. Все Испортил ИИ, какой самый сладкий чит для новичков. Но в одном я уверен точно, никогда в точных дисциплинах не побеждала гуманитарная лабузня, как долго не хвалили питон за его простоту и кучу фичей, это та же лобузня, которая со временем погаснет, а группа С будет развиваться дальше. Разве что позаимствует какие то мелкие элементы из ушедшего в древность питона, или GO. На мой взгляд такие языки, как заплатки на штаны, которые нужно срочно подлатать, пройдет время и все придут к мнению что они устарели. Таких заплаток будет еще оченьмного. А группа С языков, это как манекен, который постепенно из квадратного безформенного скелета превращается в полноценный живой образ на протяжении десятков лет. Именно точность процессов под капотом дают тот самый непревзрйденный звук двигателя у известного бренда. А эти заплатки звучат как копии китайских авто, все красиво и дорого но чувствуется где-то подвох.

miklin-ag
29.12.2025 08:33Разные языки используются для разных же целей. А ваша "группа C языков", это кажется вообще что-то из эзотерики - не понятно, почему вы в одну кучу сложили C и C#

Nagg
29.12.2025 08:33В C# любая рекурсия (т.е. вызов функцией самой себя) требует O(n) памяти только для стека
Это не так, JIT компилятор где сможет, прекрасно расставляет тейл коллы сам (а в очень редких ситуациях может даже развернуть в цикл). tail. prefix который использует F# это больше как обязательное требование к рантайму, в духе "мне все равно как, сделай тут tail call, в случае если быстрый (имплицитный) тейл-колл нельзя вставить, джиту придется вставлять специальный хелпер колл от чего будет удар по перфу.
Я не думаю что есть хоть какие шансы на появление этого в синтаксисе C#, хз зачем вы его тут перечислили.

navferty
29.12.2025 08:33Вот тоже, помню ещё лет 5 назад экспериментировал с рекурсией. Если компилировать метод с рекурсивным вызовом в последней инструкции в Release конфигурации, то реально он компилируется как цикл.
В этом можно убедиться, если намеренно сделать рекурсию бесконечной. Переполнения стека не происходит, и программа крутится бесконечно (в отличие от Debug mode, где stack overflow exception происходит практически сразу после запуска).

equmag
29.12.2025 08:33JiT действительно может, но Roslyn просто не эмитит ему эти инструкции, потому что это меняет семантику, а оптимизации по определению не должны менять результат исполнения программы.
Мне было бы очень интересно посмотреть на примеры, которые стабильно эмитят tail call потестить

Nagg
29.12.2025 08:33Какую именно это меняет семантику и результат программы? наличие или нет StackOverflowException? это не семантика

Nagg
29.12.2025 08:33Мне было бы очень интересно посмотреть на примеры, которые стабильно эмитят tail call потестить
вот вам 2 примера https://godbolt.org/z/9ne5K5G16

equmag
29.12.2025 08:33Должен отметить, предложение о хвостовой рекурсии есть в IL (поскольку есть в F#), но было отклонено на уровне LDM. Причина: ломает стек трейс, сильно травмирует отладку, есть комментарий Мэдса на тему.
Из планов на .NET11 известны ещё closed модификатор, nullable async/foreach, развивается unsafe блок в статический анализатор как было с nullable reference types, top-level methods и ещё всякого разного по мелочи.
Так-то да, из крупных анонсов ждем Union types и Runtime async (+extension everything), но об этом уже давно известно, ещё со времён .Net9. Самое интересное как по мне происходит в нишевых гитхаб коммитах

Nagg
29.12.2025 08:33развивается unsafe блок в статический анализатор как было с nullable reference types
Там скорее про то что большое кол-во public API начнут требовать unsafe{} контекст, т.к. они не безопасны. Остальное вокруг этого.

gen_dalf
29.12.2025 08:33Скоро нужно будет уточнять каким подмножеством C# ты владеешь. Стили и наборы используемых фич будут ощущаться как отдельные языки программирования.
Gromilo
Чёт страшно мне. На бэкендах привык разделять асинхронный и синхронный код, как код с IO и код без IO. Код без IO является ещё и чистыми функциями по возможности. Позволяет делить методы на части вида: грузим, что-то делаем, сохраняем.
Просто помню время, когда данные грузились в недрах каких-то функцих и этого нельзя понять, пока не просмотришь ВСЁ.