C# (C Sharp) programming
По всем вопросам- @notxxx1 Реестр РКН: https://clck.ru/3Fk3kb #VRHSZ
Show more📈 Analytical overview of Telegram channel C# (C Sharp) programming
Channel C# (C Sharp) programming (@csharp_ci) in the Russian language segment is an active participant. Currently, the community unites 18 314 subscribers, ranking 7 306 in the Technologies & Applications category and 36 810 in the Russia region.
📊 Audience metrics and dynamics
Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 18 314 subscribers.
According to the latest data from 19 June, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by 4 over the last 30 days and by 2 over the last 24 hours, overall reach remains high.
- Verification status: Not verified
- Engagement rate (ER): The average audience engagement rate is 19.46%. Within the first 24 hours after publication, content typically collects 7.55% reactions from the total number of subscribers.
- Post reach: On average, each post receives 3 563 views. Within the first day, a publication typically gains 1 382 views.
- Reactions and interaction: The audience actively supports content: the average number of reactions per post is 0.
- Thematic interests: Content is focused on key topics such as .net, api, логика, архитектура, string.
📝 Description and content policy
The author describes the resource as a platform for expressing subjective opinions:
“По всем вопросам- @notxxx1
Реестр РКН: https://clck.ru/3Fk3kb
#VRHSZ”
Thanks to the high frequency of updates (latest data received on 20 June, 2026), the channel maintains relevance and a high level of publication reach. Analytics show that the audience actively interacts with content, making it an important point of influence in the Technologies & Applications category.
ExecutionContext в .NET Core теперь является неизменяемым, что упрощает передачу контекста и делает его передачу более распространенной.
⏩Логический CallContext в .NET Core больше не существует, а его функции моделируются через AsyncLocal<T>
⏩В .NET Core глобальная очередь ThreadPool реализована как ConcurrentQueue<T>, что позволяет оптимизировать выделение памяти.
⏩Реализация метода AwaitUnsafeOnCompleted в .NET Core отличается от .NET Framework, что приводит к более эффективному использованию памяти.
📎 Статья
📎 На английском
@csharp_ciNullReferenceException со следующим сообщением:
Object reference not set to an instance of an object (В экземпляре объекта не задана ссылка на объект)Что же это значит, и как исправить код? ⏩В двух словах Вы пытаетесь воспользоваться чем-то, что равно
null (или Nothing в VB.NET). Это означает, что либо вы присвоили это значение, либо вы ничего не присваивали.
Как и любое другое значение, null может передаваться от объекта к объекту, от метода к методу. Если нечто равно null в методе "А", вполне может быть, что метод "В" передал это значение в метод "А".
⏩Более подробно
Если среда выполнения выбрасывает NullReferenceException, то это всегда означает: вы пытаетесь воспользоваться ссылкой. И эта ссылка не инициализирована (или уже не инициализирована).
Это означает, что ссылка равна null, а вы не сможете вызвать методы через ссылку, равную null, как тут:
string foo = null;
foo.ToUpper();
Этот код выбросит исключение NullReferenceException на 2 строке, потому что вы не можете вызвать метод ToUpper() у ссылки на string, равной null.
⏩Отладка
Как определить источник ошибки?
Общие рекомендации: поставьте точки останова в ключевых местах, изучите значения переменных, расположив курсор мыши над переменной, либо открыв панели для отладки: Watch, Locals, Autos.
Если вы хотите определить место, где значение ссылки устанавливается (или нет), нажмите ПКМ на её имени и выберите "Find All References". Затем вы можете поставить точки останова на каждой найденной строке и запустить приложение в режиме отладки. Каждый раз, когда отладчик остановится на точке останова, вы можете удостовериться, что значение верное.
Так вы придёте к месту, где значение ссылки не должно быть null, и определите, почему не присвоено верное значение.
📎 Очень подробное обсуждение этой проблемы с примерами
@csharp_ciIExceptionHandler.
А вот и полезная статья о том, как это делать.
⏩Вкратце о IExceptionHandler
IExceptionHandler — это интерфейс, который предоставляет разработчику обратный вызов для обработки известных исключений в центральном расположении.
IExceptionHandler реализации регистрируются путем вызова IServiceCollection.AddExceptionHandler. Время существования экземпляра IExceptionHandler — одноэлементное. Можно добавить несколько реализаций, и они вызываются в порядке регистрации.
Если обработчик исключений обрабатывает запрос, он может вернуться true к остановке обработки. Если исключение не обрабатывается обработчиком исключений, то элемент управления возвращается к поведению по умолчанию и параметрам из по промежуточного слоя. Для обработки и необработанных исключений создаются различные метрики и журналы.
📎 Статья
📎 Доки от Windows, как обрабатывать ошибки
@csharp_ciasync Task UpdateFoo()
{ ...
await SaveAsync();
}
async Task UpdateBar()
{ ...
await SaveAsync();
}
async Task UpdateBaz()
{ ...
await SaveAsync();
}
async Task SaveAsync()
{ // здесь нужно сделать так,
// чтобы одновременно обрабатывался только 1 запрос
// по окончании которого проверялось бы не было ли ещё запросов
// и если были, то обновление запускалось бы ещё 1 раз (сразу за всё "накопленное")
// и так пока есть обновления по окончании очередной обработки
}
Как это можно нормально написать? Для того, чтобы зайти один раз — понятно, SemaphoreSlim, видимо (с WaitAsync). А вот остальное как лучше сделать?
▶️Вариант решения.
⏩Общий пример, берём System.Threading.Channels.Channel<T>:
private readonly Channel<T> _channel = Channel<T>.CreateUnbounded();
⏩Пишем метод разрегребания:
private Task _workerTask;
private async Task WorkerAsync()
{
ChannelReader<T> reader = _channel.Reader;
List<T> list = new();
// ждём здесь, если в канале пусто
while (await reader.WaitToReadAsync())
{
// забираем всё что есть
// ну или можно счётчиком ограничить максимальное количество выгребаемых данных за раз
while (reader.TryRead(out T data))
{
list.Add(data);
}
// пачка собрана, погнали. это можно в try-catch завернуть, чтобы воркер не падал
await UseAsync(list);
list.Clear();
}
}
⏩Стартуем воркер:
_workerTask = WorkerAsync();Чтобы закинуть в канал:
_channel.Writer.TryWrite(x);⏩Чтобы закрыть канал (насовсем), и чтобы метод
WorkerAsync завершился, нужно вызвать:
_channel.Writer.Complete();
await _workerTask;
Вот и все дела 🙃
@csharp_ciasync/await — Stephen Cleary. Вводная статья
*️⃣ Статья об устройстве async/await под капотом. Не обязательно заучивать всю машину состояний под await, но тут как с блоком итератора yield - код пишется, а руки трясутся.
*️⃣ На этом этапе может начаться каша в голове и встреча с SynchronizationContext. Начать можно с этой статьи на MSDN. Но если она покажется душной, переходите к пункту 5.
*️⃣ Второй гигант, и тоже Stephen. Я советую перечитать все статьи обоих, что можно найти. Но продолжая тему контекста синхронизации — эта статья крайне важна для тех, кто тренируется в консольных приложениях. Вопрос об асинхронности/многопоточности уходит после нее. И небольшой, но классный ответ на StackOverflow о TaskScheduler.
*️⃣ Но если вопрос все же не ушел — There is no thread. Также советую загуглить словосочетание из этой статьи — naturally-asynchronous operations.
*️⃣ Для закрепления пунктов 4,5,6 можно почитать о Task.Run (и комплексных случаях использования многопоточности и асинхронности). Внутри этого блока статей много полезных ссылок и на другие материалы.
*️⃣ Лучшие практики от Cleary. Кстати, у него есть книга по асинхронности, можно ознакомиться при желании.
*️⃣ Обработка исключений.
@csharp_ciMutate (без использования ключевого слова unsafe), чтобы на консоль вывелось «404». Сигнатуру функции не менять, замыкания не ловить
const string constStr = "000";
Mutate(constStr);
var nonConst = "000";
Console.WriteLine(nonConst);
void Mutate(string str)
{
// write your code here
}
Вот пример моего решения, которое полностью устроило лида, который меня собесил
void Mutate(string str)
{
GCHandle handle = GCHandle.Alloc(str, GCHandleType.Pinned);
IntPtr pointer = handle.AddrOfPinnedObject();
Marshal.WriteByte(pointer, 0, (byte)'4');
Marshal.WriteByte(pointer, 4, (byte)'4');
handle.Free();
}
Весь смысл кроется в том, как работают строки в .net (интернирование), что такое pinned object и как работать с unmanaged кодом.
Идея интернирования строк состоит в том, чтобы хранить в памяти только один экземпляр типа String для идентичных строк. При старте нашего приложения виртуальная машина создаёт внутреннюю хэш-таблицу, которая называется таблицей интернирования (иногда можно встретить название String Pool).
Pinned Object Heap (POH, Куча Закрепленных Объектов). В отличие от других видов кучи, эта доступна разработчикам явно (что не характерно для сборщика мусора).
@csharp_ciDateTime — использовать метод расширения Humanize, который возвращает время и дату на естественном языке. Например:
using Humanizer;
DateTime now = DateTime.Now;
DateTime yesterday = now.AddDays(-1);
DateTime tomorrow = now.AddDays(1);
DateTime nextWeek = now.AddDays(7);
Console.WriteLine(now.Humanize()); // сейчас
Console.WriteLine(yesterday.Humanize()); // вчера
Console.WriteLine(tomorrow.Humanize()); // через 23 часа
Console.WriteLine(nextWeek.Humanize()); // через 6 дней
Как видите, метод Humanize возвращает строку, которая легко воспринимается и зависит от текущих времени и даты. Он также учитывает различные временные отношения, такие как сегодня, вчера, завтра, а также будущие или прошлые даты.
🔵Еще один способ гуманизации объекта DateTime — использовать метод расширения Humanize с булевым параметром, указывающим, отображать относительное время или нет. Относительное время — это строка, которая представляет, сколько времени прошло с или пройдет до конкретного момента. Например:
using Humanizer;
DateTime anHourAgo = DateTime.Now.AddHours(-1);
DateTime anHourLater = DateTime.Now.AddHours(1);
Console.WriteLine(anHourAgo.Humanize()); // час назад
Console.WriteLine(anHourLater.Humanize()); // через 59 минут
🔵Как-то вот так можно использовать Humanizer для управления датой и временем.
📎 Подробнее можно почитать тут
@csharp_ci
Available now! Telegram Research 2025 — the year's key insights 
