Оптимизируем nullable-аннотации с помощью [NotNullWhen(true)]
Если вы используете nullable-аннотации в C#, скорее всего сталкивались с предупреждениями CS8602/CS8603.
Часть этих сообщений действительно помогает ловить потенциальные null-референции, однако в более сложных методах компилятор не всегда способен учесть пользовательские проверки и трактует значения как "возможно null", даже когда они проверены.
Эту проблему могут решить атрибуты из
Ниже показан пример, как
1. Без использования атрибута, получаем предупреждение
2. С использованием атрибута
Зачем это нужно
Меньше проверок на null — сокращается объtм кода.
Явные контракты в сигнатуре — упрощается чтение и ревью.
Точнее статический анализ — компилятор концентрируется на реальных ошибках.
Другие атрибуты, которые стоит знать
Посты на LinkedIn, Medium
Если вы используете nullable-аннотации в C#, скорее всего сталкивались с предупреждениями CS8602/CS8603.
Часть этих сообщений действительно помогает ловить потенциальные null-референции, однако в более сложных методах компилятор не всегда способен учесть пользовательские проверки и трактует значения как "возможно null", даже когда они проверены.
Эту проблему могут решить атрибуты из
System.Diagnostics.CodeAnalysis, позволяющие формально описать контракты методов.Ниже показан пример, как
[NotNullWhen(true)] устраняет лишние предупреждения в классическом Try*-паттерне.1. Без использования атрибута, получаем предупреждение
bool TryGetDomain(string? url, out string? domain)
{
if (url is null || !url.Contains("://"))
{
domain = null;
return false;
}
domain = url.Split("://")[1];
return true; // здесь domain гарантированно не null
}
if (TryGetDomain(link, out var d))
{
Console.WriteLine(d.Length); // Предупреждение CS8602 «возможен null»
}
2. С использованием атрибута
[NotNullWhen(true)] анализатор понимает что при true, out-параметр не будет null.bool TryGetDomain(
string? url,
[NotNullWhen(true)] out string? domain)
{
if (url is null || !url.Contains("://"))
{
domain = null;
return false; // при false null допустим
}
domain = url.Split("://")[1];
return true; // при true null невозможен
}
if (TryGetDomain(link, out var d))
{
Console.WriteLine(d.Length); // без варнингов и лишних проверок
}
Зачем это нужно
Меньше проверок на null — сокращается объtм кода.
Явные контракты в сигнатуре — упрощается чтение и ревью.
Точнее статический анализ — компилятор концентрируется на реальных ошибках.
Другие атрибуты, которые стоит знать
[MaybeNullWhen(true)] — метод возвращает true, однако значение может быть null.
[NotNullIfNotNull("param")] — если входной параметр не null, результат тоже не будет null.
[MemberNotNull("Field")] — метод гарантирует инициализацию поля или свойства до выхода.
[DoesNotReturnIf(true)] — метод не возвращает управление при выполнении условия (обычно выбрасывает исключение).Посты на LinkedIn, Medium
👍15🔥3
Как добавить юнит-тесты в легаси‑проект
Может возникнуть вопрос - зачем писать тесты для старого кода?
Давайте рассмотрим несколько причин:
— Защита ключевой логики, ошибка в которой может повлечь финансовые потери. Представьте, что в методе спрятан сложный расчёт цены или процентной ставки. Тест гарантирует, что будущие изменения не сломают его.
— Быстрая отладка. Вместо настройки БД под определенный кейс, SMTP‑сервера и других сервисов, вы можете протестировать нужный кусок кода отдельно.
— Пошаговый рефакторинг. Полная переписка проекта — это риск. Вынося небольшие части в тестируемые единицы, вы получаете мгновенные плюсы и уверенность для более масштабных изменений в будущем.
Подход "Простой объект" (Humble Object)
Чтобы начать писать тесты, не нужна идеальная архитектура. С шаблоном Humble Object:
1. Выносите бизнес‑логику в отдельный класс без внешних зависимостей.
2. Оставляете доступ к базе, отправку email, логирование и прочую инфраструктуру в исходном методе.
3. Пишете тесты только для этого нового простого класса. Остальной код не меняется.
Пример
Вот пример контроллера, который смешивает вычисления с вызовами email, базы данных и логирования. Тестирование такого кода напрямую потребует замокать EF Core, DateTime.Now, SMTP и логгер одновременно
Выносим расчет цены в отдельный класс
Пишем тесты
Сейчас контроллер просто связывает компоненты
Теперь вы можете начать тестировать легаси‑код сразу, без масштабного рефакторинга.
Достаточно просто вынести основную логику в небольшие классы, которые легко тестировать. Даже несколько тестов критических методов может начать приносить пользу.
Посты на LinkedIn, Medium
Может возникнуть вопрос - зачем писать тесты для старого кода?
Давайте рассмотрим несколько причин:
— Защита ключевой логики, ошибка в которой может повлечь финансовые потери. Представьте, что в методе спрятан сложный расчёт цены или процентной ставки. Тест гарантирует, что будущие изменения не сломают его.
— Быстрая отладка. Вместо настройки БД под определенный кейс, SMTP‑сервера и других сервисов, вы можете протестировать нужный кусок кода отдельно.
— Пошаговый рефакторинг. Полная переписка проекта — это риск. Вынося небольшие части в тестируемые единицы, вы получаете мгновенные плюсы и уверенность для более масштабных изменений в будущем.
Подход "Простой объект" (Humble Object)
Чтобы начать писать тесты, не нужна идеальная архитектура. С шаблоном Humble Object:
1. Выносите бизнес‑логику в отдельный класс без внешних зависимостей.
2. Оставляете доступ к базе, отправку email, логирование и прочую инфраструктуру в исходном методе.
3. Пишете тесты только для этого нового простого класса. Остальной код не меняется.
Пример
Вот пример контроллера, который смешивает вычисления с вызовами email, базы данных и логирования. Тестирование такого кода напрямую потребует замокать EF Core, DateTime.Now, SMTP и логгер одновременно
[HttpPost("create")]
public IActionResult Create(OrderDto dto)
{
var customer = _db.Customers.Find(dto.CustomerId);
var now = DateTime.Now;
decimal subtotal = dto.Lines.Sum(l => l.Price * l.Qty);
// Скидка на черную пятницу
if (now.Month == 11 && now.Day >= 25 && now.Day <= 30)
subtotal *= 0.8m;
decimal vat = subtotal * 0.12m;
decimal total = subtotal + vat;
customer.Balance -= total;
_db.SaveChanges();
_smtp.Send("sales@corp", customer.Email,
"Thanks for your order", $"Total = {total:C}");
_log.Write($"{now:u} Order {dto.Id} for {customer.Id} = {total}");
return Ok(new { id = dto.Id, total });
}Выносим расчет цены в отдельный класс
public class OrderPricer
{
private readonly IClock _clock;
private const decimal VatRate = 0.12m;
// в .NET 8 и выше можно использовать встроенный TimeProvider вместо IClock
public OrderPricer(IClock clock) => _clock = clock;
public decimal CalculateTotal(IEnumerable<OrderLineDto> lines)
{
decimal subtotal = lines.Sum(l => l.Price * l.Qty);
var now = _clock.UtcNow;
// Скидка на черную пятницу
if (now.Month == 11 && now.Day >= 25 && now.Day <= 30)
subtotal *= 0.8m;
decimal vat = subtotal * VatRate;
return subtotal + vat;
}
}
Пишем тесты
public class FixedClock : IClock
{
public DateTime UtcNow { get; init; }
}
public class OrderPricerTests
{
[Fact]
public void CalculatesTotalWithVat_NoDiscount()
{
var clock = new FixedClock { UtcNow = new DateTime(2025, 7, 19) };
var pricer = new OrderPricer(clock);
var total = pricer.CalculateTotal(new[]
{
new OrderLineDto { Price = 100, Qty = 1 }
});
Assert.Equal(112m, total);
}
// остальные тесты
}
Сейчас контроллер просто связывает компоненты
[HttpPost("create")]
public IActionResult Create(OrderDto dto)
{
var customer = _db.Customers.Find(dto.CustomerId);
var pricer = new OrderPricer(_clock);
decimal total = pricer.CalculateTotal(dto.Lines);
customer.Balance -= total;
_db.SaveChanges();
_smtp.Send("sales@corp", customer.Email,
"Thanks for your order", $"Total = {total:C}");
_log.Write($"{_clock.UtcNow:u} Order {dto.Id} for {customer.Id} = {total}");
return Ok(new { id = dto.Id, total });
}Теперь вы можете начать тестировать легаси‑код сразу, без масштабного рефакторинга.
Достаточно просто вынести основную логику в небольшие классы, которые легко тестировать. Даже несколько тестов критических методов может начать приносить пользу.
Посты на LinkedIn, Medium
🔥7✍6
Как подключить локальный MCP сервер к GitHub Copilot
MCP (Model Context Protocol) описывает, как ИИ-агент взаимодействует с внешними инструментами. Это простой способ встроить ваши процессы в Copilot Chat.
Для этого поста я написал MCP-сервер, который запускается локально (пример на TypeScript. Поддержка .NET уже в превью).
Этот MCP сравнивает c помощью Git две ветки и помогает провести раннее код-ревью прямо в Copilot Chat.
Что сделаем
— Поднимем сервер с тремя функциями:
— Подключим его к Copilot через mcp.json.
— Запустим промпт и получим обзор пулл-реквеста.
Зачем это разработчику
— Подключайте готовые серверы, оборачивайте свои приложения, скрипты в MCP серверы для расширения возможностей Copilot или других ИИ агентов.
— Прокачиваете навыки работы с ИИ сегодня это требование к AI-ready developer.
— Все операции выполняются в привычном интерфейсе Copilot Chat.
Шаги
— Клонируйте репозиторий https://github.com/sigmade/Git-MCP-Server
— Выполните команды ниже
— В папке build появится
— В
— Откройте любой проект в VS Code с двумя ветками в моем случае это
— Убедитесь что MCP стал доступен в VS Code, для этого в Copilot Chat в режиме Agent нажмите на кнопку Configure Tools... в выпадающем списке появится список доступных инструментов, найдите секцию MCP Server в ней должен отобразиться наш MCP - simple-merge-review а так же его функции
— В чат введите промпт например -
Copilot сам поймет какой MCP сервер нужен и какие функции использовать, после чего соберет диффы и покажет изменения, улучшения и риски.
*Если вы используете Cursor возможно ему придется явно прописать в промпт какой MCP использовать.
Итог
MCP дает разработчику возможность подключать любые скрипты, API или внутренние сервисы к ИИ-агенту и использовать их в Copilot Chat для автоматизации рутины и расширения возможностей для работы с ИИ агентами
MCP (Model Context Protocol) описывает, как ИИ-агент взаимодействует с внешними инструментами. Это простой способ встроить ваши процессы в Copilot Chat.
Для этого поста я написал MCP-сервер, который запускается локально (пример на TypeScript. Поддержка .NET уже в превью).
Этот MCP сравнивает c помощью Git две ветки и помогает провести раннее код-ревью прямо в Copilot Chat.
Что сделаем
— Поднимем сервер с тремя функциями:
quick_merge_summary, show_merge_diff, show_file_diff.— Подключим его к Copilot через mcp.json.
— Запустим промпт и получим обзор пулл-реквеста.
Зачем это разработчику
— Подключайте готовые серверы, оборачивайте свои приложения, скрипты в MCP серверы для расширения возможностей Copilot или других ИИ агентов.
— Прокачиваете навыки работы с ИИ сегодня это требование к AI-ready developer.
— Все операции выполняются в привычном интерфейсе Copilot Chat.
Шаги
— Клонируйте репозиторий https://github.com/sigmade/Git-MCP-Server
— Выполните команды ниже
npm install
npm run build
npm run start
— В папке build появится
index.js.— В
C:\Users\YourUserName\AppData\Roaming\Code\User создайте mcp.json и укажите путь к сбилженному файлу index.js.— Откройте любой проект в VS Code с двумя ветками в моем случае это
master и new-feature .— Убедитесь что MCP стал доступен в VS Code, для этого в Copilot Chat в режиме Agent нажмите на кнопку Configure Tools... в выпадающем списке появится список доступных инструментов, найдите секцию MCP Server в ней должен отобразиться наш MCP - simple-merge-review а так же его функции
quick_merge_summary, show_merge_diff, show_file_diff.— В чат введите промпт например -
Из ветки new-feature в master будет создан пулл-реквест. Сделай предварительное код-ревью
Copilot сам поймет какой MCP сервер нужен и какие функции использовать, после чего соберет диффы и покажет изменения, улучшения и риски.
*Если вы используете Cursor возможно ему придется явно прописать в промпт какой MCP использовать.
Итог
MCP дает разработчику возможность подключать любые скрипты, API или внутренние сервисы к ИИ-агенту и использовать их в Copilot Chat для автоматизации рутины и расширения возможностей для работы с ИИ агентами
🔥5👍4
Чистая архитектура против многослойной
В своем недавнем посте я рассказывал, как структурирую свои приложения, используя всего три слоя:
Сегодня я хочу подробно остановиться на ключевом отличии многослойной архитектуры от чистой - инверсии зависимостей.
Многослойная архитектура
В многослойной архитектуре API вызывает методы класса
Чистая архитектура с инверсией зависимостей
В чистой архитектуре вызовы происходят через абстракции.
Этот принцип лежит в основе создания поддерживаемого кода, и о нем часто спрашивают на собеседованиях.
Итог
Инвертируя зависимости, вы делаете свой слой
В своем недавнем посте я рассказывал, как структурирую свои приложения, используя всего три слоя:
API, Core (бизнес-логика) и Infrastructure (работа с базой данных, кэшем и внешними сервисами).Сегодня я хочу подробно остановиться на ключевом отличии многослойной архитектуры от чистой - инверсии зависимостей.
Многослойная архитектура
В многослойной архитектуре API вызывает методы класса
Core (UseCase), а Core в свою очередь вызывает методы класса Infrastructure (Repository). Такое разделение уже помогает распределить обязанности, но Core все еще знает о конкретных классах из Infrastructure. Это усложняет изоляцию и тестирование доменной логики.Чистая архитектура с инверсией зависимостей
В чистой архитектуре вызовы происходят через абстракции.
Core зависит от интерфейсов, а конкретные классы подключаются только во время выполнения. Поток управления остается прежним, но тестировать становится намного проще - мы можем подставлять моки и проверять доменную логику в полной изоляции.Этот принцип лежит в основе создания поддерживаемого кода, и о нем часто спрашивают на собеседованиях.
Итог
Инвертируя зависимости, вы делаете свой слой
Core чистым и тестируемым. Это ускоряет разработку и снижает риски при изменении требований. Сделайте инверсию зависимостей фундаментальной частью своего инструментария, чтобы обеспечить гибкость и надежность вашего кода по мере его роста. Для более глубокого погружения в тему, рекомендую Архитектурные принципы и Распространенные архитектуры веб-приложений👍13
Популяризирую C# среди казахстанского IT комьюнити. Ну и кстати подписывайтесь на меня в инстаграме https://www.ddinstagram.com/p/DNpRRw5swpJ https://www.instagram.com/landromad?igsh=MW51ZDM4aG04OGtjdA%3D%3D&utm_source=qr
👍14🔥5
Фича-флаги в .NET с IFeatureManager
Где пригодится
— Временное включение или быстрое отключение фичи, например при релизе новой версии или хотфиксе
— Отключение проблемного функционала при сбоях
— A/B-тесты
— Временные сценарии, такие как акции
Как это устроено
Регистрируем Feature Management в DI, проверяем состояние флага через
В итоге поведение приложения можно менять конфигурацией, без нового деплоя.
Такой подход экономит время, снижает риск ошибок при релизах и дает команде больше контроля над функциональностью прямо в продакшене.
IFeatureManager из пакета Microsoft.FeatureManagement управляет фича-флагами в .NET. Он позволяет выбирать нужную ветку логики во время работы приложения.Где пригодится
— Временное включение или быстрое отключение фичи, например при релизе новой версии или хотфиксе
— Отключение проблемного функционала при сбоях
— A/B-тесты
— Временные сценарии, такие как акции
Как это устроено
Регистрируем Feature Management в DI, проверяем состояние флага через
IFeatureManager и задаем значения в appsettings.json. При необходимости добавляем фильтры например, TimeWindow активирует флаг только в заданном интервале времени.В итоге поведение приложения можно менять конфигурацией, без нового деплоя.
Такой подход экономит время, снижает риск ошибок при релизах и дает команде больше контроля над функциональностью прямо в продакшене.
👍17🔥3
Как из Visual Studio 2022 работать с файлами в корне решения
В Visual Studio 2022 неудобно работать с файлами и папками в корневой директории, где лежит
Это особенно заметно, когда нужно быстро править/добавить конфиги, документы или служебные каталоги (например, .github с copilot-instructions md - лишь один из частых кейсов).
Мы, конечно, можем вместо решения открыть сразу корневую папку. Однако чаще удобнее работать именно с открытым
В VS Code это решено наличием полноценного File Explorer рядом с Solution Explorer.
В VS2022 аналог можно получить через расширение
Что дает File Explorer в VS2022
— Полный доступ ко всем файлам и папкам в корне репозитория, а не только к проектам из решения.
— Меньше переключений между IDE и проводником Единое рабочее окно Solution Explorer + файловый эксплорер.
Как настроить
—
— Установите и перезапустите Visual Studio.
— В Solution Explorer появится папка которая отображает содержимое корневой папки репозитория/решения
Если вы часто работаете с файлами в корне репозитория (конфиги, CI/CD, документацию, тот же .github), это расширение - must-have.
Пост на LinkedIn, Medium
В Visual Studio 2022 неудобно работать с файлами и папками в корневой директории, где лежит
.sln. Solution Explorer (Обозреватель решения) показывает состав решения, а не реальную структуру репозитория - многие папки/файлы остаются вне обозревателя. Это особенно заметно, когда нужно быстро править/добавить конфиги, документы или служебные каталоги (например, .github с copilot-instructions md - лишь один из частых кейсов).
Мы, конечно, можем вместо решения открыть сразу корневую папку. Однако чаще удобнее работать именно с открытым
Solution Explorer.В VS Code это решено наличием полноценного File Explorer рядом с Solution Explorer.
В VS2022 аналог можно получить через расширение
File Explorer от Mads Kristensen. Что дает File Explorer в VS2022
— Полный доступ ко всем файлам и папкам в корне репозитория, а не только к проектам из решения.
— Меньше переключений между IDE и проводником Единое рабочее окно Solution Explorer + файловый эксплорер.
Как настроить
—
Extensions - Manage Extensions - найдите File Explorer (Mads Kristensen). — Установите и перезапустите Visual Studio.
— В Solution Explorer появится папка которая отображает содержимое корневой папки репозитория/решения
Если вы часто работаете с файлами в корне репозитория (конфиги, CI/CD, документацию, тот же .github), это расширение - must-have.
Пост на LinkedIn, Medium
👍5✍2
Только что вышла превью Visual Studio 2026 Insiders. Уже тестирую. https://visualstudio.microsoft.com/insiders/
🔥12👍1
Валидация appsettings.json в .NET. Предотвращаем ошибки до их появления
При построении надежных .NET-приложений одной из лучших практик является проверка конфигурации на старте.
Это позволяет избежать сценариев, когда критически важные параметры, например, feature-флаги (ранее публиковал пост о IFeatureManager), отсутствуют в
Такая ситуация опасна тем, что приложение может запуститься без ошибок, но будет работать некорректно, используя значения по умолчанию (например, false для bool типа), что приводит к трудноуловимым багам.
Вместо того чтобы столкнуться с проблемами в рантайме, лучше придерживаться подхода "fail-fast" падать сразу при запуске, если конфигурация невалидна.
Реализовать это довольно просто:
1. Создайте класс конфигурации. Определите класс, который будет представлять вашу секцию в
Однако этого будет недостаточно, так как свойство `NewDashboard` будет иметь значение по умолчанию - false.
2. Добавьте атрибуты валидации. Используйте стандартные атрибуты
3. Включите проверку при запуске. При регистрации конфигурации в Program.cs добавьте вызовы методов
Теперь, если обязательное поле будет отсутствовать в appsettings.json, приложение не запустится и выбросит исключение
Это немедленно укажет на проблему с конфигурацией, защищая систему от непредсказуемого поведения в продакшене.
Этот простой механизм шаг к созданию более стабильных и предсказуемых приложений.
Пост на LinkedIn, Medium
При построении надежных .NET-приложений одной из лучших практик является проверка конфигурации на старте.
Это позволяет избежать сценариев, когда критически важные параметры, например, feature-флаги (ранее публиковал пост о IFeatureManager), отсутствуют в
appsettings.json, что может случиться из-за неудачного разрешения конфликтов при слиянии веток или случайного удаления.{
"FeatureManagement": {
//"NewDashboard": true // Случайно закомментированный или удаленный параметр
}
}Такая ситуация опасна тем, что приложение может запуститься без ошибок, но будет работать некорректно, используя значения по умолчанию (например, false для bool типа), что приводит к трудноуловимым багам.
Вместо того чтобы столкнуться с проблемами в рантайме, лучше придерживаться подхода "fail-fast" падать сразу при запуске, если конфигурация невалидна.
Реализовать это довольно просто:
1. Создайте класс конфигурации. Определите класс, который будет представлять вашу секцию в
appsettings.json, например, FeaturesConfig.public class FeaturesConfig
{
public bool NewDashboard { get; set; }
}
Однако этого будет недостаточно, так как свойство `NewDashboard` будет иметь значение по умолчанию - false.
2. Добавьте атрибуты валидации. Используйте стандартные атрибуты
DataAnnotations, такие как [Required] или [NotNull], для обязательных полей.public class FeaturesConfig
{
[Required]
[NotNull]
public bool? NewDashboard { get; set; }
}
3. Включите проверку при запуске. При регистрации конфигурации в Program.cs добавьте вызовы методов
.ValidateDataAnnotations() и .ValidateOnStart(). который появился, начиная с .NET 6.builder.Services.AddOptions<FeaturesConfig>()
.Bind(builder.Configuration.GetSection(nameof(FeaturesConfig)))
.ValidateDataAnnotations()
.ValidateOnStart();
Теперь, если обязательное поле будет отсутствовать в appsettings.json, приложение не запустится и выбросит исключение
OptionsValidationException. Это немедленно укажет на проблему с конфигурацией, защищая систему от непредсказуемого поведения в продакшене.
Этот простой механизм шаг к созданию более стабильных и предсказуемых приложений.
Пост на LinkedIn, Medium
👍15✍4🔥4
В журнале Universum вышла моя статья -
«Применение систем искусственного интеллекта при проектировании архитектуры приложений: от требований к реализации».
В ней я разбираю интересный кейс использования GitHub Copilot при проектировании архитектуры.
С помощью заранее подготовленных промптов на основе архитектурных требований формируются записи ADR, которые можно корректировать, а затем автоматически генерируется solution с нужными проектами и библиотеками.
Полный текст: https://7universum.com/ru/tech/archive/item/20834
«Применение систем искусственного интеллекта при проектировании архитектуры приложений: от требований к реализации».
В ней я разбираю интересный кейс использования GitHub Copilot при проектировании архитектуры.
С помощью заранее подготовленных промптов на основе архитектурных требований формируются записи ADR, которые можно корректировать, а затем автоматически генерируется solution с нужными проектами и библиотеками.
Полный текст: https://7universum.com/ru/tech/archive/item/20834
👍17🔥12
Неочевидные факты из истории C#, которые стоит знать
C# - это гораздо больше, чем «еще один язык программирования».
За ним стоят годы умных экспериментов в Microsoft, которые изменили не только .NET, но и всю индустрию ПО.
Вот несколько ключевых моментов, показывающих, как C# стал настоящим инноватором:
1. 2002 - рождение C# и .NET
Главный архитектор: Андерс Хейлсберг (также создатель Turbo Pascal и Delphi).
C# 1.0 вышел вместе с .NET Framework 1.0.
Цель: создать современный, безопасный и простой язык - проще, чем C++, но с собственным взглядом Microsoft.
2. Начало 2000-х - исследовательский проект Cω (Comega)
Cω был не продуктом, а исследовательским проектом Microsoft Research.
Он объединял идеи Polyphonic C# и Xen, экспериментируя с работой с данными и конкурентностью.
Результат: Cω не стал реальным языком, но вдохновил на создание LINQ.
3. 2007 - LINQ и идеи функционального программирования
С выходом C# 3.0 Эрик Мейер привнёс идеи из функциональных языков вроде Haskell и ML.
Новые фичи: LINQ (from/where/select), лямбды, extension methods, var, анонимные типы, expression trees (используются в Entity Framework).
Эти идеи сделали C# выразительнее и позволили писать чище и мощнее.
4. 2012 - влияние F# и появление async/await
В C# 5.0 был перенесен и адаптирован async/await из F#, где уже были “async workflows”.
Это помогло уйти от старых, громоздких моделей асинхронности.
5. 2015–2021 - как C# повлиял на другие языки
Асинхронность (async/await):
Python 3.5 (2015)
JavaScript ES2017 (2017)
Kotlin 1.3 (2018)
Rust 1.39 (2019)
Swift 5.5 (2021)
Функциональный стиль (идеи LINQ):
Java Streams API (Java 8, 2014)
Вывод
C# не просто следовал трендам - он их задавал.
Он изменил то, как разработчики думают об асинхронности, данных и дизайне языков.
P.S. Интересный факт после публикации
После публикации этого поста в LinkedIn к нему оставил комментарии сам Don Syme - создатель и главный архитектор языка F#. Он подчеркнул важные моменты:
Он также отметил, что важный вклад в C# в 2000-х внесли следующие люди:
Gavin Bierman - COmega
Cédric Fournet - COmega
Nick Benton - COmega
Erik Meijer - LINQ и многое другое
Todd Proebsting - iterators
Andrew Kennedy - generics
Claudio Russo - generics
Пост на LinkedIn
C# - это гораздо больше, чем «еще один язык программирования».
За ним стоят годы умных экспериментов в Microsoft, которые изменили не только .NET, но и всю индустрию ПО.
Вот несколько ключевых моментов, показывающих, как C# стал настоящим инноватором:
1. 2002 - рождение C# и .NET
Главный архитектор: Андерс Хейлсберг (также создатель Turbo Pascal и Delphi).
C# 1.0 вышел вместе с .NET Framework 1.0.
Цель: создать современный, безопасный и простой язык - проще, чем C++, но с собственным взглядом Microsoft.
2. Начало 2000-х - исследовательский проект Cω (Comega)
Cω был не продуктом, а исследовательским проектом Microsoft Research.
Он объединял идеи Polyphonic C# и Xen, экспериментируя с работой с данными и конкурентностью.
Результат: Cω не стал реальным языком, но вдохновил на создание LINQ.
3. 2007 - LINQ и идеи функционального программирования
С выходом C# 3.0 Эрик Мейер привнёс идеи из функциональных языков вроде Haskell и ML.
Новые фичи: LINQ (from/where/select), лямбды, extension methods, var, анонимные типы, expression trees (используются в Entity Framework).
Эти идеи сделали C# выразительнее и позволили писать чище и мощнее.
4. 2012 - влияние F# и появление async/await
В C# 5.0 был перенесен и адаптирован async/await из F#, где уже были “async workflows”.
Это помогло уйти от старых, громоздких моделей асинхронности.
5. 2015–2021 - как C# повлиял на другие языки
Асинхронность (async/await):
Python 3.5 (2015)
JavaScript ES2017 (2017)
Kotlin 1.3 (2018)
Rust 1.39 (2019)
Swift 5.5 (2021)
Функциональный стиль (идеи LINQ):
Java Streams API (Java 8, 2014)
Вывод
C# не просто следовал трендам - он их задавал.
Он изменил то, как разработчики думают об асинхронности, данных и дизайне языков.
P.S. Интересный факт после публикации
После публикации этого поста в LinkedIn к нему оставил комментарии сам Don Syme - создатель и главный архитектор языка F#. Он подчеркнул важные моменты:
“Language integrated async programming was shipped first in F# in 2006 and was copied and adapted into C# in the following years.”
“The history of Generics, LINQ and async programming, iterators and more is covered tangentially in ‘The Early History of F#’
https://dl.acm.org/doi/abs/10.1145/3386325
There’s no corresponding peer reviewed paper on the history of C# unfortunately.”
Он также отметил, что важный вклад в C# в 2000-х внесли следующие люди:
Gavin Bierman - COmega
Cédric Fournet - COmega
Nick Benton - COmega
Erik Meijer - LINQ и многое другое
Todd Proebsting - iterators
Andrew Kennedy - generics
Claudio Russo - generics
Пост на LinkedIn
👍15🔥11