C# Portal | Программирование
13.3K subscribers
1.28K photos
131 videos
31 files
996 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для C#-разработчика

Сотрудничество, реклама: @devmangx

Менеджер: @Spiral_Yuri

РКН: https://clck.ru/3FocB6
Download Telegram
Виды Классов в C#

Абстрактный
Базовый класс, экземпляр которого нельзя создать. Он может содержать абстрактные и неабстрактные члены и предназначен для наследования от него.
public abstract class Vehicle
{
public abstract int Wheels { get; }
public abstract void TurnOn();
public bool Started { get; protected set; }
}

Создать экземпляр класса Vehicle нельзя, поэтому унаследуем от него. При этом класс-наследник обязан переопределить абстрактные члены:
public class Car : Vehicle
{
public override int Wheels => 4;
public override void TurnOn()
=> Started = true;
}


Запечатанный (sealed)
Специальный тип класса, который ограничивает иерархию наследования. Это предотвращает создание производных типов, что повышает безопасность кода и позволяет компилятору применять оптимизации производительности.
public sealed class Vehicle
{
}


Статический
Экземпляр статического класса нельзя создать, и от статического класса нельзя унаследовать. Все члены должны быть помечены статическими.
public static class SpeedConverter
{
public static decimal ToMph(decimal kph)
=> return kph / 1.6093m;
}


Частичный
В одном и том же пространстве имён нельзя создавать несколько классов с одним именем. Частичный класс позволяет разделить объявление класса на несколько файлов. При компиляции объявления объединяются в один класс. Нельзя дублировать члены с одной сигнатурой в разных объявлениях частичного класса:
public partial class Team
{
public Team() { }
public string Name { get; set; }
}

public partial class Team
{
public int Players { get; set; }
}


Небезопасный
Небезопасный класс позволяет использовать код с указателями:
public unsafe class MemoryReader
{
public void Read(int* value)
{
Console.WriteLine(*value);
}
}

Если вам необходимо работать с указателями, нужно включить небезопасный код в файле .csproj, установив параметр AllowUnsafeBlocks в значение true.

Запись
Запись — ссылочный тип, предназначенный для данных, а не для поведения, и по умолчанию является неизменяемой:
public record class Team(string Name, int Players);


Модификаторы доступа
- public – доступен отовсюду;
- internal – доступен внутри сборки;
- private – доступен только внутри включающего его типа;
- protected – доступен внутри включающего его типа и всех его наследников;
- file – доступен только внутри содержащего его файла исходного кода.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥94🍾2😁1🤯1
This media is not supported in your browser
VIEW IN TELEGRAM
Чилловый разработчик сделал “чёрную дыру” прямо в терминале, чтобы заставить себя делать перерывы.

Чем дольше работаешь без остановки, тем больше она растёт и начинает искажать код, как гравитационная линза.
Отдохнул — она уменьшается.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍81👎1🍾1
microservices-2025-roadmap.pdf
1.8 MB
roadmap по .NET-микросервисам с подборкой полезных материалов

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾6
Что Происходит, Когда вы Вводите google.com в Браузере?

1. Вы вводите адрес веб-сайта в адресную строку браузера.

2. Браузер сначала проверяет свой кэш. Если адрес не найден в кэше, он должен найти IP-адрес.

3. Начинается поиск DNS (представьте, что вы ищете номер телефона). Запрос проходит через различные DNS-серверы (корневой, TLD - сервер имен доменов верхнего уровня - и авторитативный). Наконец, извлекается IP-адрес.

4. Браузер инициирует TCP-соединение, начиная с рукопожатия. Например, в случае HTTP 1.1 клиент и сервер выполняют трёхстороннее TCP-рукопожатие с сообщениями SYN, SYN-ACK и ACK.

5. Браузер отправляет HTTP-запрос на сервер, и сервер отвечает файлами HTML, CSS и JS.

6. Браузер обрабатывает ответ. Он анализирует HTML-документ и создаёт деревья DOM и CSSOM.

7. Браузер выполняет код JavaScript и отображает страницу, проходя через различные этапы (токенизатор, парсер, дерево рендеринга, компоновка и отрисовка).

8. Веб-страница появляется на экране.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥43🍾1
Вышел Rider 2026.2 EAP 6.

В этом превью JetBrains улучшили отображение асинхронных стеков вызовов во время отладки.
Теперь отладчик скрывает часть шума от сгенерированных кадров, связанных с async/await и инфраструктурой Task, поэтому проще отслеживать реальный поток выполнения приложения, не продираясь через детали реализации, добавленные компилятором.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍5🤔3🍾2
Небольшой совет по написанию чистого кода:

Заменяйте сложные if-условия методами с понятными названиями.
Сложные if-ы тяжело читать.

Особенно когда они объединяют несколько разных условий.
Это можно исправить простым рефакторингом.

→ Вынесите условие в метод или переменную с говорящим именем.

Теперь само название объясняет, что именно проверяется.
Людям гораздо проще читать понятные названия, чем разбирать сложные условия в коде.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👏9👍32🔥2🍾1
Виртуальная машина vs Контейнер vs Serverless

Виртуальные машины запускают полноценную операционную систему поверх виртуализированного оборудования. Они обеспечивают высокий уровень изоляции и дают больше контроля над окружением, но требуют больше ресурсов, поскольку каждая ВМ содержит собственную ОС.

Контейнеры упаковывают приложение вместе со всеми его зависимостями и запускаются как изолированные процессы на общем ядре хостовой системы. Они легче виртуальных машин, проще переносятся между окружениями и широко используются для развертывания микросервисов.

Serverless-функции позволяют развёртывать небольшие фрагменты кода без управления базовой серверной инфраструктурой. Облачный провайдер берёт на себя выделение ресурсов, масштабирование и выполнение кода, поэтому такой подход хорошо подходит для событийно-ориентированных задач: API, задач по расписанию и обработки очередей.

В современных системах редко выбирают только один из этих подходов. Часто контейнеры работают внутри виртуальных машин, а serverless-функции используются для отдельных событийно-ориентированных сценариев, где каждая технология применяется для тех нагрузок, которым она подходит лучше всего.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾31
Перед тем как читать новый проект, я первым делом иду не в код, а в Git.

Пара команд за 2 минуты часто рассказывает о кодовой базе больше, чем час листания файлов.

Что меняют чаще всего
git log --format=format: --name-only --since="1 year ago" | sort | uniq -c | sort -nr | head -20


Показывает 20 файлов, которые меняли чаще всего за последний год. Верхние строчки списка обычно быстро находят тот самый файл, к которому все боятся прикасаться.

Кто реально поддерживает проект
git shortlog -sn --no-merges


Сразу видно распределение коммитов между разработчиками и потенциальный автобусный фактор.

Где чаще всего чинят баги
git log -i -E --grep="fix|bug|broken" --name-only --format='' | sort | uniq -c | sort -nr | head -20


Если файл часто появляется и здесь, и в списке самых изменяемых файлов — это один из главных источников технического долга.

Проект набирает темп или затухает
git log --format='%ad' --date=format:'%Y-%m' | sort | uniq -c


Количество коммитов по месяцам помогает быстро понять динамику разработки.

Как часто приходится тушить пожары
git log --oneline --since="1 year ago" | grep -iE 'revert|hotfix|emergency|rollback'


Откаты, хотфиксы и экстренные исправления многое говорят о качестве релизного процесса.

Эти команды не заменят аудит, но помогают понять, какие части системы стоит изучать в первую очередь, а какие проблемы уже давно кричат о себе через историю Git.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥174💯4🍾1
Вышел roadmap для SqlClient

https://github.com/dotnet/SqlClient/blob/main/roadmap.md

Стоит посмотреть, если тебе интересны:

- особенности работы пула соединений (connection pooling)
- сценарии аутентификации (Entra ID, MSI и другие)
- производительность и надёжность под высокой нагрузкой

На этом этапе обратная связь от сообщества ещё может повлиять на архитектурные и технические решения.

#dotnet #sqlserver

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾1
Создаём Базовый Компонент для Всех Компонентов в Blazor

При разработке Blazor-приложения может понадобиться пользовательский базовый компонент для всех остальных компонентов. Это полезно для совместного использования общих функций, таких как токены отмены, логирование или управление состоянием, во всех компонентах. Вместо добавления @inherits YourBaseComponent в каждый файл Razor, вы можете использовать файл _Imports.razor для глобальной установки базового компонента.

Создадим файл _Imports.razor в папке, к компонентам которой нужно применить базовый компонент. Все файлы Razor в этой папке и её подпапках будут наследовать указанный базовый компонент.

@inherits YourNamespace.CustomComponentBase


Файл _Imports.razor обрабатывается перед любым компонентом Razor в том же каталоге или его подкаталогах. Все компоненты затем автоматически наследуют от CustomComponentBase без необходимости объявлять @inherits в каждом файле.

Пример: CustomComponentBase с CancellationToken
Вот пример базового компонента, который предоставляет CancellationToken всем производным компонентам. Это полезно для отмены асинхронных операций при удалении компонента:

@* CustomComponentBase.razor (Razor) *@
@implements IDisposable

@code {
private readonly CancellationTokenSource
_cts = new CancellationTokenSource();

public CancellationToken
CancellationToken => _cts.Token;

public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
}


Теперь все наши компоненты могут получить доступ к свойству CancellationToken без какой-либо дополнительной настройки:

@* MyComponent.razor (Razor) *@
@* Не нужно использовать @inherits, т.к. _Imports.razor импортируется автоматически *@

<h3>Мой компонент</h3>

@code {
protected override async Task OnInitializedAsync()
{
// Используем CancellationToken из базового компонента
await LoadDataAsync(CancellationToken);
}

private async Task LoadDataAsync(CancellationToken ct)
{
// … асинхронный код …
await Task.Delay(1000, ct);
}
}


Переопределение базового компонента для конкретных компонентов
Если конкретному компоненту требуется другой базовый компонент или вообще никакой, вы можете объявить @inherits непосредственно в файле этого компонента. Явное объявление имеет приоритет над _Imports.razor:

@* MyComponent.razor (Razor) *@
@inherits ComponentBase

@* Этот компонент будет использовать ComponentBase вместо CustomComponentBase *@


Организация файлов _Imports.razor

Можно иметь несколько файлов _Imports.razor в разных папках, чтобы применять разные базовые компоненты к различным разделам приложения. Приоритет имеет ближайший файл _Imports.razor в иерархии каталогов. Например, /Components/_Imports.razor применяется ко всем компонентам в этой папке /Components/Admin/_Imports.razor применяется специально к компонентам папки Admin. Такой иерархический подход обеспечивает точный контроль над тем, какие компоненты наследуют от каких базовых классов.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👏61🍾1
Вопрос с C#-собеседования уровня Middle/Senior.
Многие разработчики на нём ошибаются

Посмотрите на код на первом слайде.

Что там видно:
ProductStock не равен null;
мы проходимся по элементам в цикле;
внутри цикла используется yield return.

Так почему всё равно появляется warning или error?
Подумайте немного... А потом откройте второй слайд и проверьте свой ответ.

Ответ 👇

yield return не останавливает выполнение цикла.
В отличие от обычного return, который сразу завершает метод, yield return лишь приостанавливает выполнение и возвращает очередной элемент последовательности.

После этого выполнение продолжается с того места, где оно было остановлено.
Поэтому, если нужно пропустить текущую итерацию, следует использовать continue.
Иначе код после yield return всё равно выполнится, что может привести к неожиданному поведению или исключениям.
Это одна из тех особенностей C#, о которых часто забывают даже опытные разработчики.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥145🍾2
Практическое применение архитектуры Vertical Slice в ASP.NET Core

https://www.telerik.com/blogs/practicing-vertical-slice-architecture-aspnet-core

Автор: Assis Zang

#aspnetcore

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5🍾1
Перестаньте использовать исключения для управления логикой приложения

Вот почему 👇

Большинство разработчиков используют исключения каждый день.

Но есть проблема: исключения подходят далеко не для всех сценариев.

Работая архитектором ПО и .NET-разработчиком, я пришёл к простому выводу:

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

👉 Исключения нужны для обработки действительно нештатных ситуаций.

Но ими не стоит заменять обычную бизнес-логику и ожидаемые условия.

Основные недостатки такого подхода:

• Непредсказуемость — по сигнатуре метода не всегда понятно, какие исключения он может выбросить

• Снижение читаемости — try/catch ломает линейный поток чтения кода

• Вложенность — отладка и навигация по коду становятся менее удобными

• Потери производительности — обработка исключений обходится дороже обычных проверок (даже с улучшениями в .NET 9)

Что использовать вместо этого?

Result Pattern

Вместо выбрасывания исключений метод возвращает объект Result.

Так успех и ошибка становятся явной частью контракта метода.

📌 Обычно объект Result содержит:

1️⃣ IsSuccess / IsError — успешно ли выполнена операция

2️⃣ Value — результат выполнения при успехе

3️⃣ Error — информация об ошибке при неудаче

Плюсы такого подхода:

↳ Более предсказуемые API

↳ Более чистый поток выполнения

↳ Проще писать unit-тесты

↳ Лучше производительность

Для этого паттерна уже есть готовые библиотеки:

• FluentResults

• CSharpFunctionalExtensions

• Ardalis.Result

• ErrorOr

Но на практике сторонние пакеты вовсе не обязательны.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🥴5🔥1🍾1
Как работает git?

На изображении схематично изображён процесс работы с Git — системой контроля версий.

Workspace: Рабочее пространство, где находятся файлы проекта (например, .git, src, index.html).
🟢Команда git add перемещает изменения в Stage (область индексации).
🟢Команда git reset отменяет индексацию изменений.

Stage: Область индексации, где изменения подготавливаются для фиксации.
🟢 Команда git commit сохраняет изменения в локальном репозитории.

Local Repository: Локальный репозиторий, где хранятся зафиксированные изменения.
🟢 Команда git push отправляет изменения в удалённый репозиторий.

Remote Repository: Удалённый репозиторий, например, на платформах GitLab, GitHub или Bitbucket.
🟢 Команда git fetch извлекает изменения с удалённого репозитория.
🟢 Команда git pull объединяет изменения удалённого и локального репозиториев (эквивалентно git fetch + git merge).

В нижней части схемы представлена последовательность действий при выполнении команды git pull. 😮

Эта схема полезна для понимания основных этапов работы с Git.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🍾2
Сравнение, которое снова разожгло споры о лаконичности языков программирования.
На скриншоте один и тот же HTTP-сервер с маршрутом "/" и ответом "Hello world" реализован на Clojure и C#.

Вариант на C# использует минимальный API из ASP.NET Core и укладывается в несколько строк.
Реализация на Clojure выглядит заметно объёмнее: отдельное описание обработчика, заголовков ответа и запуск Jetty-сервера.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🍾4
Большинство разработчиков изучают PostgreSQL в неправильном порядке.

Вот мой личный план изучения, разделённый на 7 уровней.

Не начинайте сразу с:

* тюнинга производительности
* индексов
* репликации
* партиционирования

Чтобы действительно хорошо разбираться в PostgreSQL, нужно понимать, за что отвечает каждый уровень.

1️⃣ Основы SQL

Прежде чем думать об индексах, производительности или масштабировании, нужно уверенно владеть базовым языком работы с базами данных:

* SELECT
* WHERE
* ORDER BY
* GROUP BY
* агрегатные функции
* базовые JOIN'ы
* LIMIT и OFFSET
* DISTINCT

Слабое знание SQL обычно приводит к неаккуратным запросам, лишней сложности и проблемам с производительностью в будущем.

2️⃣ Моделирование данных

Когда вы уже умеете писать запросы, следующий шаг — научиться правильно структурировать данные.

Сюда входят:

* таблицы
* схемы
* первичные ключи
* внешние ключи
* ограничения
* связи
* нормализация
* типы данных
* соглашения по именованию

Прежде чем оптимизировать базу данных, нужно её правильно спроектировать.

3️⃣ Продвинутые запросы

На этом этапе вы переходите от простых запросов к более выразительным SQL-конструкциям:

* JOIN'ы
* подзапросы
* CTE
* оконные функции
* условные выражения
* продвинутые агрегации
* запросы к JSON и JSONB
* операции с массивами

Этот уровень позволяет решать сложные бизнес-задачи непосредственно внутри базы данных.

4️⃣ Индексы

Сначала вас волнует, работает ли запрос вообще.

Потом начинает волновать, работает ли он быстро.

Здесь в игру вступают индексы.

Нужно понимать:

* индексы B-tree
* индексы GIN
* индексы GiST
* частичные индексы
* составные индексы
* уникальные индексы
* обслуживание индексов
* когда индексы помогают
* когда индексы вредят

Цель не в том, чтобы добавлять индексы везде подряд.

Цель — понимать, как ваше приложение читает данные.

5️⃣ Тюнинг производительности

На этом уровне вы учитесь анализировать, что база данных делает на самом деле.

Важные темы:

* EXPLAIN
* EXPLAIN ANALYZE
* планирование запросов
* анализ использования индексов
* VACUUM
* ANALYZE
* раздувание таблиц (table bloat)
* статистика
* логи медленных запросов
* настройки памяти и I/O
* настройка конфигурации

Тюнинг производительности — это не угадывание.

Это расследование.

6️⃣ Администрирование

PostgreSQL в продакшене — это не только написание запросов.

Её также нужно безопасно и надёжно эксплуатировать.

Этот уровень включает:

* роли и права доступа
* резервное копирование и восстановление
* репликацию
* мониторинг и оповещения
* пулинг соединений
* настройку безопасности
* миграции и обновления
* процессы обслуживания
* планирование аварийного восстановления

7️⃣ Масштабирование и экосистема

Масштабирование — это верхний уровень, а не отправная точка.

Сюда входят:

* партиционирование
* реплики для чтения
* высокая доступность
* логическая репликация
* шаблоны шардирования
* управляемые сервисы PostgreSQL
* инструменты наблюдаемости
* интеграции с экосистемой
* расширения вроде PostGIS, pg_trgm и TimescaleDB

Прочный фундамент — ключ к изучению чего угодно.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍73🍾2
Воскресенский совет для .NET-разработчиков: перестаньте использовать DateTime.UtcNow напрямую в коде.
Используйте TimeProvider.

Тогда приложение будет работать с реальными часами, а в тестах вы сможете подставлять фейковые часы и вручную двигать время вперёд.
Небольшая абстракция — зато тесты становятся гораздо удобнее.

На примере:
public sealed class TrialService(TimeProvider clock)
{
public bool IsExpired(DateTimeOffset startedAt) =>
clock.GetUtcNow() >= startedAt.AddDays(14);
}


В тесте:
var clock = new FakeTimeProvider(startedAt);
var service = new TrialService(clock);

clock.Advance(TimeSpan.FromDays(15));

Assert.True(service.IsExpired(startedAt));


Никаких задержек, никаких сюрпризов от DateTime.UtcNow. Просто перематываете время вперёд в тестах и проверяете нужный сценарий.

https://learn.microsoft.com/ru-ru/dotnet/standard/datetime/timeprovider-overview

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🍾2🔥1
Нашёл интересный инструмент для поиска и устранения дублирующегося кода.

Называется Deslop. Написан на Rust, но работает не только с Rust-проектами — поддерживает Python, Dart и C#.
Инструмент анализирует кодовую базу, находит дубликаты и помогает избавиться от повторяющихся фрагментов. Автор предлагает просто установить его в VS Code или любой другой форк редактора и использовать прямо в процессе разработки.

Автор проекта также собрал отдельную подборку статей и исследований, которые легли в основу алгоритмов Deslop.

Если в проекте много копипасты и похожих реализаций, инструмент может помочь быстро найти кандидатов на рефакторинг.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🍾1
🚀 В .NET 11 Preview 6 появилась новая возможность из C# 15 — extension indexers.

Теперь индексаторы можно объявлять прямо внутри extension-блоков:
static class E
{
extension(...)
{
int this[...] { get => ...; set => ...; }
}
}


Это позволяет добавлять индексаторы к существующим типам без изменения их исходного кода, так же как сегодня работают extension methods.
Фича уже влита в C# 15 Preview и доступна в .NET 11 Preview 6. 🔥

https://github.com/dotnet/csharplang/blob/main/proposals/extension-indexers.md

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7👎4🔥1🍾1
Docker-ошибка, которую я вижу почти в каждом junior Dockerfile:
COPY . .
RUN npm install


должно быть:
COPY package*.json ./
RUN npm install
COPY . .


почему это важно?

docker кэширует каждую инструкцию как отдельный слой
исходный код меняется с каждым коммитом
поэтому COPY . . ломает кэш, и всё после него (включая npm install) пересобирается с нуля при каждой сборке
если поменять порядок, слой с установкой зависимостей остаётся в кэше даже при изменении кода, потому что он зависит только от package.json
одна перестановка строк. экономит 40+ секунд на каждой пересборке. кэшируй зависимости, а не код.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍125🍾1