Как C# разработчик, вы по-любому знаете класс
Dictionary. В качестве значений вы, скорее всего, использовали классы. А знаете ли вы, что в
Dictionary можно использовать структуры? Не стоит бояться того, что структуры копируются при передаче в метод или возврате из него. Есть способ этого избежать, и это работает быстро.Собственно, об этом и говорится в статье, а вот некоторые выводы из неё:
Dictionary лучше воспользоваться классом CollectionsMarshal. GetValueRefOrAddDefault и GetValueRefOrNullRef позволяют получать элементы словаря по ссылке. Это, в свою очередь, может положительно сказаться на производительности кода при относительно большом количестве операций поиска в словаре.@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
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Здесь и сборники рецептов, и теория по сетевому программированию, и паттерны проектирования приложений, и описание принципов работы асинхронного кода
Даже ссылки на обзоры IDE и инструменты для работы с C#
Рекомендую)
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Начнём с того, что
event и delegate — это 2 абсолютно разных вещи. Разница между полем-делегатом и event'ом примерно такая же, как между полем и свойством: event иногда выглядит как делегатное поле. Давайте разберёмся в этом.delegate — это класс, содержащий в себе «шаблон» метода, то есть, сигнатуру метода. Переменная делегатного типа — объект типа MulticastDelegate (точнее, производного от него), который может содержать один или несколько объектов, представляющих собой методы с совместимой с «шаблоном» сигнатурой (контр- и ковариантность немного усложняет картину). То есть это как бы переменная, которая может содержать функции. Для таких переменных определена операция +, которая комбинирует слагаемые-функции в одну новую функцию, и симметричная операция -. Эти операции автоматически порождают производные операции += и -=.event же — это просто пара методов в классе, обозначаемых как add и remove, и имеющих произвольную семантику, выбранную программистом. (Аналог — геттер и сеттер свойства.) В имплементации по умолчанию для event'а заводится скрытое поле делегатного типа, а add/remove добавляют или убирают из него методы (под lock'ом). (Чтобы немного запутать картину, это скрытое поле доступно по тому же имени, что и event.) Функции add/remove, составляющие event, *вызываются* соответственно как += и -=. Никаких операций +/-, разумеется, нету.@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Держите очень полезную roadmap от Михаила Флёнова, автора «Библия C#»
Это подборка видео и статей, которые помогут на пути C# Web разработчика
Пользуйтесь)
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Что выведет на экран этот код?
Anonymous Quiz
24%
10 10
45%
10 20
31%
Возникнет ошибка времени выполнения
null или пустую коллекцию? Есть ли общепринятая практика?На запрос «дайте мне список всех пользователей» пустая коллекция имеет очевидный смысл: «окей, вот вам список всех пользователей, их ровно 0 штук».
С другой стороны, возвращённый
null может означать что угодно: «я не знаю, сколько пользователей», «количество пользователей ещё не подсчитано», «текущая база данных вообще не имеет понятия пользователь», что угодно.То есть смысл пустой коллекции всегда ясен, смысл
null не определён.null — так вы избавите пользователя от необходимости писать утомительный код проверок на null и, соответственно, избавите его от большого количества NullReferenceException, если он таковой код написать забыл. Хорошим примером могут быть случаи, когда коллекции задействованы в цепочках методов видаvar res = FirstMethod().SecondMethod().ThirdMethod();
и в случае, если коллекция равна
null, вся цепочка может быть обрушена исключением, тогда как проверки на null превратят этот лаконичный и довольно элегантный синтаксис в кашу из вложенных if-ов. Для коллекций это можно считать общепринятой практикой.Кстати, в LINQ именно так и делается. Например, следующий код вполне нормально работает без выбрасывания исключений, хотя очевидно, что ни один из элементов коллекции не удовлетворяет условию лямбды в
Where:var res2 = new[] { 1, 2, 3 }.Where(x => x > 10).Select(x => x);@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Если вы хотите глубже разобраться, как работать с элементами ProgressBar и BackgroundWorker в C#, с элементом FolderBrowserDialog, а также с событиями DoWork, ProgressChanged, RunWorkerCompleted, то большая часть этой статьи может принести вам много нового опыта.
Уверен, будет полезно)
Будущее приложение по поиску файлов будет выглядеть как на изображении
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
out даёт такой же результат, как и с ref.Такой код:
private void func(out string value)
{
value = "Hello World!";
}
Даёт такой же эффект, как и:
private void func(ref string value)
{
value = "Hello World!";
}
В чём же разница между
out и ref?out — это выходной параметр, а ref — входно-выходной.Для
ref-параметра вы должны передать его инициализированным, и можете пользоваться его исходным значением. А для out-параметра вы не обязаны инициализировать его перед вызовом функции, не можете использовать его значение в функции до присваивания, и обязаны инициализировать его в функции.(Таким образом,
ref-параметр немного напоминает инициализированную локальную переменную, а out-параметр — неинициализированную.)Иллюстрация:
private void func1(out string value)
{
Console.WriteLine(value); // нельзя, value не инициализировано
if (false)
return; // нельзя, забыли установить значение value
value = "Hello World!";
}
string s1;
func1(out s1);
private void func2(ref string value)
{
Console.WriteLine(value); // можно
if (false)
return; // не проблема, у value остаётся старое значение
value = "Hello World!";
}
string s2;
func2(ref s2); // нельзя, функция имеет право использовать значение,
// значит, оно должно быть инициализировано сначала
Таким образом,
out-параметр — это как бы дополнительное возвращаемое значение функции. А ref-параметр — просто параметр, изменения которого видны снаружи функции.@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
File:[HttpGet("file/{guid}/download")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> DownloadFile([FromRoute] Guid guid)
{
var file = await _mediaContentService.DownloadFile(guid);
return File(file.Stream, file.ContentType, file.FileName);
}Можно ли каким-либо образом реализовать ограничение на скачивание файла, чтобы, например, в единицу времени не больше N пользователей качало файл?
File — он возвращает ленивый ответ. Т.е. он не читает весь поток сразу, а ждет пока будет вызван метод от IActionResult.Чтобы эту проблему решить, надо знать, когда файл точно отправлен.
Можно сделать специальный декоратор. Например:
[ApiController]
[Route("[controller]")]
public class SampleController : ControllerBase
{
private readonly IRateLimiter _rateLimiter;
public SampleController(IRateLimiter rateLimiter)
{
_rateLimiter = rateLimiter;
}
[HttpGet("connection")]
public async Task<IActionResult> DownLoadFile(Guid file)
{
var stream = await GetFileStream(file);
return new RateLimiterFileActionResult(File(stream, "content/type", "sample.txt"), _rateLimiter);
}
}
class RateLimiterFileActionResult : IActionResult
{
private readonly IActionResult _actionResultImplementation;
private readonly IRateLimiter _rateLimiter;
public RateLimiterFileActionResult(IActionResult actionResultImplementation, IRateLimiter rateLimiter)
{
_actionResultImplementation = actionResultImplementation;
_rateLimiter = rateLimiter;
}
public async Task ExecuteResultAsync(ActionContext context)
{
try
{
await _rateLimiter.ObtainAsync(context.HttpContext.RequestAborted);
await _actionResultImplementation.ExecuteResultAsync(context);
}
finally
{
await _rateLimiter.ReleaseAsync(context.HttpContext.RequestAborted);
}
}
}
public interface IRateLimiter
{
public Task ObtainAsync(CancellationToken token);
public Task ReleaseAsync(CancellationToken token);
}
Стоит заметить, что блокировка берётся внутри метода декоратора, а не в методе контроллера.
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
В этой статье мы разберёмся с запуском C#-тестов на Linux и последующую публикацию их в открытом репозитории кода на GitHub.
План:
├╼ Устанавливаем .NET на Ubuntu 22.04├╼ Создаём проект├╼ Запускаем сборку в GitHub Actions├╼ Используем секреты в коде тестов╰╼ Размещаем секреты в GitHub Actions Secrets@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM