collection expression
), которые представляют унифицированный подход к созданию коллекций. Так, если раньше создание массивов выглядело так:int[] nums1 = { 1, 2, 3, 4 };
int[] nums2 = new int[] { }; // пустой массив
Теперь можно писать так:
int[] nums1 = [ 1, 2, 3, 4 ];
int[] nums2 = []; // пустой массив
Аналогичным образом можно использовать выражения коллекций для создания других типов коллекций:
List<int> list1 = [1, 2, 3, 4];
List<int> list2 = []; // пустой список
Span<int> span1 = [1, 2, 3, 4];
Primary constructors
) позволяют добавлять параметры к определению класса/структуры и использовать эти параметры внутри класса/структуры:var tom = new Person("Tom", 38);
Console.WriteLine(tom);
public class Person(string name, int age)
{
public Person(string name) : this(name, 18) { }
public string Name => name;
public int Age => age;
public override string ToString() => $"name: {name}, age: {age}";
}
Здесь для класса
Person
определен первичный конструктор с двумя параметрами - name
и age
. Эти параметры применяются для инициализации свойств Name
и Age
и используются в методе ToString()
.За кадром для каждого параметра первичного конструктора в классе создается приватное поле, которое хранит значение параметра. Благодаря этому они могут использоваться в теле класса.
Кроме первичных конструкторов класс может определять дополнительные конструкторы, как примере выше. Но эти дополнительные конструкторы должны вызывать первичный конструктор:
public Person(string name) : this(name, 18) { }
Разумеется, это не все фичи C# 12, вот подробнее:
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
По умолчанию, при передаче в метод/возврате из метода, экземпляры значимых типов копируются, тогда как экземпляры ссылочных типов передаются по ссылке.
В 2008 была выпущена книга «Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries». В ней рекомендовалось не использовать структуры больше 16 байт, поскольку, очевидно, структуры большего размера копируются медленнее. Прошло уже 16 лет, но в сообществе C# разработчиков до сих пор популярно мнение, что производительность структур размером больше 16 байт хуже. Даже Google на запрос «recommended structure size c#» говорит, что это не более 16 байт.
Код бенчмарка очень прост. Он содержит структуры и классы размером от 4 до 160 байт, с шагом 4 байта.
Для каждой структуры и класса есть соответствующий метод, который из параметра типа int cоздаёт соответствующий экземпляр и возвращает его.
И, самое главное, есть непосредственно бенчмарк методы (картинка), каждый из которых создаёт список структур или классов. Размер списка – 1000 элементов.
В общем, после проведения тестов можно убедиться, что использование структур размером больше 16 байт не ухудшает производительность. Сейчас этой границей является размер 64 байта.
А ты знал про это?
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Чисто академическое задание но почему бы и нет
Вот неправильное решение, подумай, какие в нём ошибки и напиши по красоте.
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Эти 2 варианта ниже неправильные, они не работают:
—
List = (InputField.text).ToList
—
List = InputField.text
Так как
InputField.text
это тип string
, я не могу преобразовать его в List<string>
. Что в итоге делать?InputField
в List<string>
вот так:string text = InputField.text;
string[] lines = text.Split(Environment.NewLine);
string[] lines = text.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
List<string> list = lines.ToList();
Но если нет необходимости список модифицировать, лучше оставить массив.
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Итак задача:
как создать бесконечно повторяющийся метод в 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
Необходимо извлечь все 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?
— И так далее.
Регулярное выражение очень быстро становится нечитаемым. Какие есть другие варианты?
Проверенный игрок на поле парсеров. В отличие от 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 — бесплатная .NET-библиотека с открытым исходным кодом, которая предлагает набор методов для манипулирования строками, числами, датами, временем, временными интервалами, цифрами и величинами в удобном для человеческого восприятия виде.
Работа со временем и датой — одна из самых распространенных и муторных задач в любом приложении. Пользователи ожидают увидеть дату и время в формате, который будет легко восприниматься и соответствовать контексту.
Один из самых простых способов гуманизировать объект
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 минут
@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
Асинхронность вызывает большие проблемы у многих, но выход есть — вот:
async/await
— Stephen Cleary. Вводная статьяawait
, но тут как с блоком итератора yield
- код пишется, а руки трясутся.SynchronizationContext
. Начать можно с этой статьи на MSDN. Но если она покажется душной, переходите к пункту 5.TaskScheduler
.@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Что выведет на экран это код?
Anonymous Quiz
44%
с :1,4,5,7,2 l :1,4,5,7,3
30%
с :1,4,5,6,7,2 l :1,4,5,7,3
10%
с :1,4,5,6,7,2 l :1,4,5,6,7,2
16%
с :1,4,5,6,7,2,3 l :1,4,5,6,7,2,3
Хотелось бы как-то "накопить" обновления, пока обработчик занят. Причём, сами данные для обновления уже "накапливаются", об этом заботиться не нужно, нужно только разрулить "накопление" запросов к обработчику, чтобы когда обработчик освободиться обрабатывать не все накопившиеся запросы на обновление по отдельности, а за один раз сразу весь пакет "обновлений" обработать.
Вот так происходит сейчас:
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
Относительно недавно на свет появился ASP.NET Core 8.0, и теперь можно обрабатывать ошибки с помощью
IExceptionHandler
. А вот и полезная статья о том, как это делать.
IExceptionHandler
IExceptionHandler
— это интерфейс, который предоставляет разработчику обратный вызов для обработки известных исключений в центральном расположении.IExceptionHandler
реализации регистрируются путем вызова IServiceCollection.AddExceptionHandler
. Время существования экземпляра IExceptionHandler
— одноэлементное. Можно добавить несколько реализаций, и они вызываются в порядке регистрации.Если обработчик исключений обрабатывает запрос, он может вернуться
true
к остановке обработки. Если исключение не обрабатывается обработчиком исключений, то элемент управления возвращается к поведению по умолчанию и параметрам из по промежуточного слоя. Для обработки и необработанных исключений создаются различные метрики и журналы.@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM