C# (C Sharp) programming
18.7K subscribers
757 photos
38 videos
8 files
675 links
По всем вопросам- @haarrp

C# - обучающий канал Senior C# разработчика.

@ai_machinelearning_big_data - Machine learning

@itchannels_telegram - 🔥лучшие ит-каналы

@csharp_ci - C# академия

@pythonlbooks- книги📚

Реестр РКН: https://clck.ru/3Fk3kb
Download Telegram
🖥 Создание бесконечно повторяющегося метода в C#

Итак задача:
как создать бесконечно повторяющийся метод в C#, который работает на протяжении работы приложения?
Предположим, метод должен через определенное количество времени выводить какую-то информацию на экран; он должен работать вне зависимости от действий пользователя.


Если в двух словах, то для этого можно использовать асинхронность.
Итак, создаём:
private async Task RunLoopAsync(CancellationToken token)
{
try
{
while (true)
{
// ... что-то сделать
await Task.Delay(1000, token); // подождать одну секунду
}
}
catch (OperationCanceledException)
{ } // сработала отмена, ничего не делать
}

и вот так это можно использовать:
private CancellationTokenSource _cts;

private async void StartLoop()
{
if (_cts != null)
return;
try
{
using (_cts = new CancellationTokenSource())
{
await RunLoopAsync(_cts.Token);
}
}
catch (Exception ex)
{
// ... ex.Message
}
_cts = null;
}

private void StopLoop()
{
_cts?.Cancel();
}


📎 Читать подробнее

@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Что выведет на экран это код?
Anonymous Quiz
23%
100 100
11%
1000 1000
65%
100 1000
🖥 Как распарсить HTML в .NET?

🔜 Итак, реальный кейс:
Необходимо извлечь все URL из атрибутов href тегов a в HTML странице. Можно попробовать воспользоваться регулярными выражениями:
Uri uri = new Uri("http://google.com/search?q=test");
Regex reHref = new Regex(@"<a[^>]+href=""([^""]+)""[^>]+>");
string html = new WebClient().DownloadString(uri);
foreach (Match match in reHref.Matches(html))
Console.WriteLine(match.Groups[1].ToString());


Но возникает множество потенциальных проблем:
— Как отфильтровать только специфические ссылки, например, по CSS классу?
— Что будет, если кавычки у атрибута другие?
— Что будет, если вокруг знака равенства пробелы?
— Что будет, если кусок страницы закомментирован?
— Что будет, если попадётся кусок JavaScript?
— И так далее.
Регулярное выражение очень быстро становится нечитаемым. Какие есть другие варианты?


🔜 Для парсинга HTML используйте AngleSharp

Проверенный игрок на поле парсеров. В отличие от CsQuery, написан с нуля вручную на C#. Также включает парсеры других языков.

API построен на базе официальной спецификации по JavaScript HTML DOM. Изначально содержал в некоторых местах странности, непривычные для разработчиков на .NET (например, при обращении к неверному индексу в коллекции будет возвращён null, а не выброшено исключение), но разработчик в конце концов сдался и исправил самые жуткие костыли. Что-то ушло само, например, Microsoft BCL Portability Pack. Что-то осталось, например, пространства имён очень гранулярные, даже базовое использование библиотеки требует три using и т. п.), но в целом ничего критичного.

Обработка HTML простая, к примеру вот:
IHtmlDocument angle = new HtmlParser().ParseDocument(html);
foreach (IElement element in angle.QuerySelectorAll("a"))
Console.WriteLine(element.GetAttribute("href"));


📎 Читать подробнее

@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Humanizer C#

Humanizer — бесплатная .NET-библиотека с открытым исходным кодом, которая предлагает набор методов для манипулирования строками, числами, датами, временем, временными интервалами, цифрами и величинами в удобном для человеческого восприятия виде.

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


🔵Форматирование DateTime в удобочитаемый вид
Один из самых простых способов гуманизировать объект DateTime — использовать метод расширения 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
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Задачка с собеседования от Сбера:

Вставьте код функции Mutate (без использования ключевого слова 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
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Ловите полезные ссылки для изучения асинхронности в C#

Асинхронность вызывает большие проблемы у многих, но выход есть — вот:

*️⃣ Во-первых, стоит прочитать весь блок статей на MSDN

*️⃣ Первый гигант async/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_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Как "схлопнуть" вызовы, чтобы вызываемый код не "захлебнулся"?

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

Хотелось бы как-то "накопить" обновления, пока обработчик занят. Причём, сами данные для обновления уже "накапливаются", об этом заботиться не нужно, нужно только разрулить "накопление" запросов к обработчику, чтобы когда обработчик освободиться обрабатывать не все накопившиеся запросы на обновление по отдельности, а за один раз сразу весь пакет "обновлений" обработать.

Вот так происходит сейчас:
async 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_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Обработка ошибок с помощью IExceptionHandler в ASP.NET Core 8.0

Относительно недавно на свет появился ASP.NET Core 8.0, и теперь можно обрабатывать ошибки с помощью IExceptionHandler.
А вот и полезная статья о том, как это делать.

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

IExceptionHandler реализации регистрируются путем вызова IServiceCollection.AddExceptionHandler. Время существования экземпляра IExceptionHandler — одноэлементное. Можно добавить несколько реализаций, и они вызываются в порядке регистрации.

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

📎 Статья
📎 Доки от Windows, как обрабатывать ошибки

@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥Что такое NullReferenceException, и как исправить?

Итак кейс: выполняется некоторый код, выбрасывается исключение NullReferenceException со следующим сообщением:
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_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Годное видео о рефакторинге кода C#

В частности, в ролике идёт речь о таких вещах как:

Переименование переменных и методов
— Улучшает ясность и понятность кода, делая его самодокументируемым.
Пример: система управления контентом, где переменные и методы не дают ясного понимания их назначения.

Извлечение интерфейса
— Разделение определения операции от ее реализации, улучшение модульности, упрощение тестирования и увеличение гибкости кода.
Пример: система обработки платежей, где класс реализует методы для каждого типа платежа, но добавление новых способов обработки может быть проблематичным.

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

📎 Кликабельный план ролика
📎 Youtube

@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Интерактивный учебник по C#

Возможно, вы в курсе, что этот учебник существует. В любом случае, это отличный способ ознакомиться с C# и .NET

Пока что заданий в нём не много, а оглавление выглядит так:
— Запуск первой программы C#
— Объявление и использование переменных
— Работа со строками
— Другие действия со строками
— Строки поиска
— Выполнение задачи

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

📎 Учебник

@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Как на самом деле работает Async/Await в C#

Держите полезную статью о том, как реализована асинхронность в C#.

О чём статья?
Статья обсуждает различия в реализации асинхронных методов в .NET Framework и .NET Core.

В .NET Framework выделяется много объектов, связанных с асинхронными вызовами, что приводит к большому объему памяти.

В .NET Core реализация асинхронных методов значительно изменилась, что привело к уменьшению выделения памяти.

ExecutionContext в .NET Core теперь является неизменяемым, что упрощает передачу контекста и делает его передачу более распространенной.

Логический CallContext в .NET Core больше не существует, а его функции моделируются через AsyncLocal<T>

В .NET Core глобальная очередь ThreadPool реализована как ConcurrentQueue<T>, что позволяет оптимизировать выделение памяти.

Реализация метода AwaitUnsafeOnCompleted в .NET Core отличается от .NET Framework, что приводит к более эффективному использованию памяти.

📎 Статья
📎 На английском

@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
«А что там собственно нового в C# 12?»

Интересное видео, в котором Евгений Федотов рассказывает о нововведениях в C# 12

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

Collection-оператор, объединение массивов в одну коллекцию.

Атрибут эксперимента, для указания на экспериментальный код.

Атрибут для перехвата методов.

Использование перехватчиков для логирования и других целей.

Возможность указывать функциональные значения для лямда-выражений.

Возможность выдавать псевдоним любому типу или кортежу.

и ещё освещается много всего, так что будет полезно

📎 Кликабельный план видео
📎 Видео

@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM