C# (C Sharp) programming
По всем вопросам- @notxxx1 Реестр РКН: https://clck.ru/3Fk3kb #VRHSZ
Показати більше📈 Аналітичний огляд Telegram-каналу C# (C Sharp) programming
Канал C# (C Sharp) programming (@csharp_ci) у мовному сегменті Російська є активним учасником. На даний момент спільнота об'єднує 18 144 підписників, посідаючи 7 070 місце в категорії Технології та додатки та 36 441 місце у регіоні Росія.
📊 Показники аудиторії та динаміка
З моменту свого створення невідомо, проект продемонстрував стрімке зростання, зібравши аудиторію у 18 144 підписників.
За останніми даними від 01 вересня, 2026, канал демонструє стабільну активність. Хоча за останні 30 днів спостерігається зміна кількості учасників на -54, а за останні 24 години на 20, загальне охоплення залишається високим.
- Статус верифікації: Не верифікований
- Рівень залученості (ER): Середній показник залученості аудиторії становить 13.79%. Протягом перших 24 годин після публікації контент зазвичай збирає 7.32% реакцій від загальної кількості підписників.
- Охоплення публікацій: В середньому кожен допис отримує 2 503 переглядів. Протягом першої доби публікація в середньому набирає 1 329 переглядів.
- Реакції та взаємодія: Аудиторія активно підтримує контент: середня кількість реакцій на один пост – 0.
- Тематичні інтереси: Контент зосереджений навколо ключових тем, таких як .net, api, логика, архитектура, string.
📝 Опис та контентна політика
Автор описує ресурс як майданчик для висловлення суб'єктивної думки:
“По всем вопросам- @notxxx1
Реестр РКН: https://clck.ru/3Fk3kb
#VRHSZ”
Завдяки високій частоті оновлень (останні дані отримано 02 вересня, 2026), канал підтримує актуальність та високий рівень охоплення публікацій. Аналітика показує, що аудиторія активно взаємодіє з контентом, що робить його важливою точкою впливу в категорії Технології та додатки.
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_ci