dir.by  
  Поиск  
Программирование, разработка, тестирование
C# (язык программирования)
Асинхронное программирование в C# (теория)
  Посмотрели 16919 раз(а)       Комментариев 1  
 Последний комментарий: (3 июня 2022 17:17) "Оно включается в сигнатуру метода точно так... читать...       написать комментарий...
 Асинхронное программирование в C# (теория) 
последнее обновление: 13 марта 2019
Контекст выполнения (ExecutionContext)
Контекст выполнения (ExecutionContext) - это родительский контекст (контейнер для других конекстов), включающий все остальные контексты.
Он не имеет собственного поведения, а служит только для запоминания и передачи контекста и используется такими компонентами .NET, как класс Task.
Контекст синхронизации (SynchronizationContext)
Контекст синхронизации (SynchronizationContext) - позволяет возобновить выполнение метода в конкретном потоке.
Текущий контекст SynchronizationContext – это свойство текущего потока. Идея в том, что всякий раз, как код исполняется в каком-то специальном потоке, мы
можем получить текущий контекст синхронизации и сохранить его.
Впоследствии этот контекст можно использовать для того, чтобы продолжить исполнение кода в том потоке, в котором оно было начато.

В классе SynchronizationContext есть важный метод Post, который гарантирует, что переданный делегат будет исполняться в правильном контексте.

Важно! В момент приостановки метода при встрече оператора await текущий контекст SynchronizationContext сохраняется.
Далее, когда метод возобновляется, компилятор вставляет вызов Post, чтобы исполнение возобновилось в запомненном контексте.
Асинхронное программирование
Код называется асинхронным, если он запускает какую-то длительную операцию, но не дожидается ее завершения. Противоположностью является блокирующий код, который ничего не делает, пока операция не завершится.

К числу таких длительных операций можно отнести:
• сетевые запросы;
• доступ к диску;
• продолжительные задержки.

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

Всякий раз, запуская новый поток или пользуясь классом ThreadPool, вы пишете асинхронную программу, потому что текущий поток может продолжать заниматься другими вещами.
Чем так хорош асинхронный код?
Асинхронный код освобождает поток, из которого был запущен. И это очень хорошо по многим причинам.

Часто существует лишь один поток, способный выполнить определенную задачу (например, поток пользовательского интерфейса) и, если не освободить его быстро, то приложение перестанет реагировать на действия пользователя.

Но самым важным мне кажется тот факт, что асинхронное выполнение открывает возможность для параллельных вычислений.
Что такое async?
В версии C# 5.0 Microsoft добавила механизм, предстающий в виде двух новых ключевых слов: async и await.

Механизм async встроен в компилятор и без поддержки с его стороны не мог бы быть реализован в библиотеке. Компилятор преобразовывает исходный код, то есть действует примерно по тому же принципу, что в случае лямбда-выражений и итераторов в предыдущих версиях C#.
Серверный код веб-приложения
У ASP.NET-приложений на веб-сервере нет ограничения на единственный поток, как в случае программ с пользовательским интерфейсом. И тем не менее асинхронное выполнение может оказаться весьма полезным, так как для таких приложений характерны длительные операции, особенно запросы к базе данных.

В зависимости от версии IIS может быть ограничено либо общее число потоков, обслуживающих веб-запросы, либо общее число одновременно обрабатываемых запросов. Если большая часть времени обработки запроса уходит на обращение к базе данных, то увеличение числа одновременно обрабатываемых запросов может повысить пропускную способность сервера

Помните: основная отличительная особенность асинхронного кода состоит в том, что поток, начавший длительную операцию, освобождается для других дел.
В случае ASP.NET этот поток берется из пула потоков, поэтому после запуска длительной операции он сразу же возвращается в пул и может затем использоваться для обработки других запросов. Таким образом, для обработки одного и того же количества запросов требуется меньше потоков.
Введение в класс Task
Библиотека Task Parallel Library была включена в версию .NET Framework 4.0. Важнейшим в ней является класс Task, представляющий выполняемую операцию. Его универсальный вариант, Task<T>, играет роль обещания вернуть значение (типа T), когда в будущем, по завершении операции, оно станет доступно.

Как мы увидим ниже, механизм async в C# 5.0 активно пользуется классом Task. Но и без async классом Task, а особенно его вариантом Task, можно воспользоваться при написании асинхронных программ. Для этого нужно запустить операцию, которая возвращает Task<T>, а затем вызвать метод ContinueWith для регистрации обратного вызова.
Это называется асинхронность вручную потому что используем метод ContinueWith.

Заметка на будующее:
Класс Task умеет в частности обрабатывать исключения и работать с контекстами синхронизации SynchronizationContext.
Мы увидим, что это полезно, когда требуется выполнить обратный вызов в конкретном потоке (например, в потоке пользовательского интерфейса).
Написание асинхронных методов:
1-ый шаг это пометка метода ключевым словом async.
Оно включается в сигнатуру метода точно так же, как, например, слово static.

2-ой шаг мы должны дождаться завершения скачивания, воспользовавшись ключевым словом await.
С точки зрения синтаксиса C#, await – это унарный оператор, такой же как оператор ! или оператор приведения типа (type).
Он располагается слева от выражения и означает, что нужно дождаться завершения асинхронного выполнения этого выражения.

На заметку!
Метод, помеченный ключевым словом async, автоматически не становится асинхронным.
Async-методы лишь упрощают использование других асинхронных методов. Они начинают исполняться синхронно, и так происходит до тех пор, пока не встретится вызов асинхронного метода внутри оператора await.
В этот момент сам вызывающий метод становится асинхронным.
Если же оператор await не встретится, то метод так и будет выполняться синхронно до своего завершения.
Task и await
Я говорил, что класс Task представляет выполняемую операцию, а его подкласс Task<T> – операцию, которая в будущем вернет значение типа T. Можно считать, что Task<T> – это обещание вернуть значение типа T по завершении длительной операции.
Оба класса Task и Task<T> могут представлять асинхронные операции, и оба умеют вызывать ваш код по завершении операции. Чтобы воспользоваться этой возможностью вручную, необходимо вызвать метод ContinueWith, передав ему код, который должен быть выполнен, когда длительная операция завершится. Именно так и поступает оператор await, чтобы выполнить оставшуюся часть async-метода.

Если применить await к объекту типа Task<T>, то мы получим выражение await, которое само имеет тип T.
Это означает, что результат оператора await можно присвоить переменной, которая используется далее в методе, что мы и видели в примерах.
Однако если await применяется к объекту неуниверсального класса Task, то получается предложение await, которое ничему нельзя присвоить (как и результат метода типа void). Это разумно, потому что класс Task не обещает вернуть значение в качестве результата, а представляет лишь саму операцию.
Тип значения, возвращаемого асинхронным методом
Метод, помеченный ключевым словом async, может возвращать значения трех типов:
• void
• Task
• Task, где T – некоторый тип.

Никакие другие типы не допускаются, потому что в общем случае
исполнение асинхронного метода не завершается в момент возврата управления. Как правило, асинхронный метод ждет завершения длительной операции, то есть управление-то он возвращает сразу, но результат в этот момент еще не получен и, стало быть, недоступен вызывающей программе.

Я провожу различие между типом возвращаемого методом значения (например, Task<string>) и типом результата, который нужен вызывающей программе (в данном случае string).
В обычных, не асинхронных, методах тип возвращаемого значения совпадает с типом результата, тогда как в асинхронных методах они различны – и это очень существенно.

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

Async-методы, возвращающие тип Task, позволяют вызывающей программе ждать завершения асинхронной операции и распространяют исключения, имевшие место при ее выполнении.

Если значение результата несущественно, то метод типа async Task предпочтительнее метода типа async void, потому что вызывающая программа получает возможность узнать о завершении операции, что упрощает упорядочение задач и обработку исключений.
Async, сигнатуры методов и интерфейсы
Ключевое слово async указывается в объявлении метода, как public или static.
Однако спецификатор async не считается частью сигнатуры метода, когда речь заходит о переопределении виртуальных методов, реализации интерфейса или вызове.
То есть в отношении переопределения методов и реализации интерфейсов, слово async полностью игнорируется.

В объявлениях методов интерфейса слово async запрещено просто потому, что в этом нет необходимости. Если в интерфейсе объявлен метод, возвращающий тип Task, то в реализующем интерфейс классе этот метод может быть помечен словом async, а может быть и не помечен – на усмотрение программиста.
Приостановка и возобновление метода
Когда поток исполнения программы доходит до оператора await, должны произойти две вещи:

1) Текущий поток должен быть освобожден, чтобы поведение программы было асинхронным. С привычной, синхронной, точки зрения это означает, что метод должен вернуть управление.

2) Когда задача Task, погруженная в оператор await, завершится, ваш метод должен продолжить выполнение с того места, где перед этим вернул управление, как будто этого возврата никогда не было.

Чтобы добиться такого поведения, метод должен приостановить выполнение, дойдя до await, и возобновить его впоследствии.
Состояние метода
Чтобы стало яснее, сколько работы должен выполнить компилятор C#, встретив в программе оператор await, я перечислю, какие именно аспекты состояния метода необходимо сохранить.

Во-первых, запоминаются все локальные переменные метода, в том числе:
• параметры метода
• все переменные, определенные в текущей области видимости
• все прочие переменные, например счетчики циклов
• переменную this, если метод не статический

В результате после возобновления метода окажутся доступны все переменные-члены класса.
Всё это сохраняется в виде объекта в куче .NET, обслуживаемой сборщиком мусора. Таким образом, встретив await, компилятор выделяет память для объекта, то есть расходует ресурсы, но в большинстве случае это не приводит к потере производительности.
C# также запоминает место, где встретился оператор await.

контекст синхронизации, который среди прочего позволяет возобновить выполнение метода в конкретном потоке.
мое: Task помогает востанавливать контекст синхронизации, перед обратным вызовом

ExecutionContext - это родительский контекст, включающий все остальные контексты. Он не имеет собственного поведения, а служит только для запоминания и передачи контекста и используется такими компонентами .NET, как класс Task.
Когда нельзя использовать await
Оператор await можно использовать почти в любом месте метода, помеченного ключевым словом async.

Оператор await может встречаться внутри блока try, но не внутри блоков catch или finally.

В блоке catch часто, а в блоке finally всегда, исключение еще находится в фазе раскрутки стека и позже может быть возбуждено в блоке повторно.

Если использовать в этой точке await, то стек окажется другим, и определить в этой ситуации поведение повторного возбуждения исключения было бы очень сложно.
Напомню, что await всегда можно поставить не внутри блока catch, а после него, для чего следует либо воспользоваться предложением return, либо завести булевскую переменную, в которой запомнить, возбуждала ли исходная операция исключение. Например, вместо такого некорректного в C# кода:

  C#  
try
{
     page = await webClient.DownloadStringTaskAsync("http://aaa.com");
}
catch (WebException)
{
     page = await webClient.DownloadStringTaskAsync("http://ooo.com");
}


можно было бы написать:

  C#  
bool failed = false;

try
{
     page = await webClient.DownloadStringTaskAsync("http://aaa.com");
}
catch (WebException)
{
     failed = true;
}

if (failed)
{
     page = await webClient.DownloadStringTaskAsync("http://ooo.com");
}
Блоки lock
Ключевое слово lock позволяет запретить другим потокам доступ к объектам, с которыми в данный момент работает текущий поток.
Поскольку асинхронный метод обычно освобождает поток, в котором начал асинхронную операцию, и через неопределенно долгое время может быть возобновлен в другом потоке, то удерживать блокировку во время выполнения await не имеет смысла.
Запоминание исключений
По завершении операции в объекте Task сохраняется информация о том, завершилась ли она успешно или с ошибкой. Получить к ней доступ проще всего с помощью свойства IsFaulted, которое равно true, если во время выполнения операции произошло исключение.
Оператор await знает об этом и повторно возбуждает исключение, хранящееся в Task.
У читателя, знакомого с системой исключений в .NET, может возникнуть вопрос, корректно ли сохраняется первоначальная трассировка стека исключения при его повторном возбуждении.

Раньше это было невозможно; каждое исключение могло быть возбуждено только один раз. Однако в .NET 4.5 это ограничение снято благодаря новому классу ExceptionDispatchInfo, который взаимодействует с классом Exception с целью запоминания трассировки стека и воспроизведения ее при повторном возбуждении.

Async-методы также знают об исключениях. Любое исключение, возбужденное, но не перехваченное в async-методе, помещается в объект Task, возвращаемый вызывающей программе. Если в этот момент вызывающая программа уже ждет объекта Task, то исключение будет возбуждено в точке ожидания. Таким образом, исключение передается вызывающей программе вместе со сформированной виртуальной трассировкой стека – точно так же, как в синхронном коде.

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

Асинхронные методы до поры исполняются синхронно Выше я уже отмечал, что async-метод становится асинхронным, только встретив вызов асинхронного метода внутри оператора await. До этого момента он работает в том потоке, в котором вызван, как обычный синхронный метод.
Использование Task для операций, требующих большого объема вычислений
Иногда длительная операция не отправляет запросов в сеть и не обращается к диску, а просто выполняет продолжительное вычисление.
Разумеется, нельзя рассчитывать на то, что поток быстро выполнит, желательно избежать зависания пользовательского интерфейса.
Для этого мы должны вернуть управление потоку пользовательского интерфейса, чтобы он мог обрабатывать другие события, а длительное вычисление производить в отдельном потоке.

Класс Task позволяет это сделать, а для обновления пользовательского интерфейса по завершении вычисления мы можем, как обычно, использовать await:

  C#  
Task t = Task.Run(() => MyLongComputation(a, b));


Метод Task.Run исполняет переданный ему делегат в потоке, взятом из пула ThreadPool. В данном случае я воспользовался лямбда-выражением, чтобы упростить передачу счетной задаче локальных переменных. Возвращенная задача Task запускается немедленно, и мы можем дождаться ее завершения, как любой другой задачи:

  C#  
await Task.Run(() => MyLongComputation(a, b));


Это очень простой способ выполнить некоторую работу в фоновом потоке.
Если необходим более точный контроль над тем, какой поток производит вычисления или как он планируется, в классе Task имеется статическое свойство Factory типа TaskFactory. У него есть метод StartNew с различными перегруженными вариантами для управления вычислением:

  C#  
Task t = Task.Factory.StartNew(() => MyLongComputation(a, b),
cancellationToken,
TaskCreationOptions.LongRunning,
taskScheduler);

WhenAll Ожидание завершения нескольких задач.
В разделе «Task и await» выше мы видели, как просто организовать выполнение несколько параллельных асинхронных задач, – нужно запустить их по очереди, а затем ждать завершения каждой. Потом мы узнаем, что необходимо дождаться завершения каждой задачи,
иначе можно пропустить исключения.

Для решения этой задачи можно воспользоваться методом Task.
WhenAll, который принимает несколько объектов Task и порождает агрегированную задачу, которая завершается, когда завершены все исходные задачи. Вот простейший вариант метода WhenAll (имеется также перегруженный вариант для коллекции универсальных объектов Task<T>):

Task WhenAll(IEnumerable<Task> tasks)

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

Универсальный вариант WhenAll возвращает массив, содержащий
результаты отдельных поданных на вход задач Task. Это сделано скорее для удобства, чем по необходимости, потому что доступ к исходным объектам Task сохраняется, и ничто не мешает опросить их свойство Result, так как точно известно, что все задачи уже завершены.
WhenAny Ожидание завершения любой задачи из нескольких.
Часто возникает также ситуация, когда требуется дождаться завершения первой задачи из нескольких запущенных. Например, так бывает, когда вы запрашиваете один и тот же ресурс из нескольких источников и готовы удовлетвориться первым полученным ответом.

Task<Task<T>> WhenAny(IEnumerable<Task<T>> tasks)

В ситуации, когда возможны исключения, пользоваться методом WhenAny следует с осторожностью. Если вы хотите знать обо всех исключениях, произошедших в программе,
то необходимо ждать каждую задачу, иначе некоторые исключения могут быть потеряны. Воспользоваться методом WhenAny и просто забыть об остальных задачах – всё равно, что перехватить все исключения и игнорировать их.
Это достойное порицания решение, которое может впоследствии привести к тонким ошибкам и недопустимым состояниям программы.

Метод WhenAny возвращает значение типа Task<Task<T>>. Это означает, что по завершении задачи вы получаете объект типа Task<T>.
Он представляет первую из завершившихся задач и поэтому гарантированно находится в состоянии «завершен». Но почему нам возвращают объект Task, а не просто значение типа T?

Чтобы мы знали, какая задача завершилась первой, и могли отменить все остальные и дождаться их завершения.

  C#  
Task<Task<Image>> anyTask = Task.WhenAny(tasks);
Task<Image> winner = await anyTask;
Image image = await winner; // Этот оператор всегда завершается синхронно

AddAFavicon(image);
foreach (Task<Image> eachTask in tasks)
{
     if (eachTask != winner)
     {
          await eachTask;
     }
}


Нет ничего предосудительного в том, чтобы обновить пользовательский интерфейс, как только будет получен результат первой завершившейся задачи (winner), но после этого необходимо дождаться остальных задач, как сделано в коде выше. При удачном стечении обстоятельств все они завершатся успешно, и на выполнении программы это никак не отразится. Если же какая-то задача завершится с ошибкой, то вы сможете узнать причину и исправить ошибку.
CancellationToken Отмена асинхронных операций.
Отмена асинхронных операций связывается с типом CancellationToken

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

  C#  
Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)


При вызове метода ThrowIfCancellationRequested отмененного объекта CancellationToken возбуждается исключение типа OperationCanceledException.

  C#  
foreach (var x in thingsToProcess)
{
     cancellationToken.ThrowIfCancellationRequested(); // Обработать x ...
}


Библиотека Task Parallel Library знает, что такое исключение представляет отмену, а не ошибку, и обрабатывает его соответственно. Например, в классе Task имеется свойство IsCanceled, которое автоматически принимает значение true, если при выполнении async-метода произошло исключение OperationCanceledException.

Удобной особенностью подхода к отмене, основанного на маркерах CancellationToken, является тот факт, что один и тот же маркер можно распространить на столько частей асинхронной операции, сколько необходимо, – достаточно просто передать его всем частям.
Неважно, работают они параллельно или последовательно, идет ли речь о медленном вычислении или удаленной операции, – один маркер отменяет всё.
До первого await
До первого await не происходит ничего интересного.
Async не планирует выполнение метода в фоновом потоке. Единственный способ сделать это – воспользоваться методом Task.Run, который специально предназначен для этой цели, или чем-то подобным.

В приложении с пользовательским интерфейсом это означает, что код до первого await работает в потоке пользовательского интерфейса.
А в веб-приложении на базе ASP.NET – в рабочем потоке ASP.NET.

Часто бывает, что выражение в строке, содержащей первый await, содержит еще один async-метод.
Поскольку это выражение предшествует первому await, оно также выполняется в вызывающем потоке.
Таким образом, вызывающий поток продолжает «углубляться» в код приложения, пока не встретит метод, действительно возвращающий объект Task.

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

К счастью, в большинстве случаев он выполняется недолго, но важно помнить, что одно лишь наличие ключевого слова async не гарантирует отзывчивости интерфейса.
Подробнее о классе SynchronizationContext
Текущий контекст SynchronizationContext – это свойство текущего потока. Идея в том, что всякий раз, как код исполняется в каком-то специальном потоке, мы можем получить текущий контекст синхронизации и сохранить его.
Впоследствии этот контекст можно использовать для того, чтобы продолжить исполнение кода в том потоке, в котором оно было начато.

Поэтому нам не нужно точно знать, в каком потоке началось исполнение, достаточно иметь соответствующий объект SynchronizationContext.

В классе SynchronizationContext есть важный метод Post, который гарантирует, что переданный делегат будет исполняться в правильном контексте.
await и SynchronizationContext
Мы знаем, что код, предшествующий первому await, исполняется в вызывающем потоке, но что происходит, когда исполнение вашего метода возобновляется после await?

На самом деле, в большинстве случаев он также исполняется в вызывающем потоке, несмотря на то, что в промежутке вызывающий поток мог делать что-то еще.
Это существенно упрощает написание кода.

Для достижения такого эффекта используется класс SynchronizationContext.

Важно!!!
В момент приостановки метода при встрече оператора await текущий контекст SynchronizationContext сохраняется.
Далее, когда метод возобновляется, компилятор вставляет вызов Post, чтобы исполнение возобновилось в запомненном контексте.
Взаимодействие с синхронным кодом
В классе Task имеется свойство Result, обращение к которому блокирует вызывающий поток до завершения задачи.

Его можно использовать в тех же местах, что await, но при этом не требуется, чтобы метод был помечен ключевым словом async или возвращал объект Task.
И в этом случае один поток занимается – на этот раз вызывающий (то есть тот, что блокируется).

  C#  
var result = MyMethodAsync().Result;

Исключения в async-методах, возвращающих Task
Большинство написанных вами async-методов возвращают значение типа Task или Task<T>. Цепочка таких методов, в которой каждый ожидает завершения следующего, представляет собой асинхронный аналог стека вызовов в синхронном коде.

Компилятор C# прилагает максимум усилий к тому, чтобы исключения, возбуждаемые в этих методах, вели себя так же, как в синхронном случае. В частности, блок try-catch, окружающий ожидаемый async-метод, перехватывает исключения, возникшие внутри этого метода

  C#  

async Task Catcher()
{
     try
     {
          await Thrower();
     }
     catch (AlexsException)
     {
          // Исключение будет обработано здесь
     }
}

async Task Thrower()
{
     await Task.Delay(100);
     throw new AlexsException();
}


Для этого C# перехватывает все исключения, возникшие в вашем async-методе. Перехваченное исключение помещается в объект Task, который был возвращен вызывающей программе. Объект Task переходит в состояние Faulted. Если задача завершилась с ошибкой, то ожидающий ее метод не возобновится как обычно, а получит исключение, возбужденное в коде внутри await.

В async-методе оно возбуждается там, где находится оператор await, а не в точке фактического вызова метода. Это становится очевидным, если разделить вызов и await.

  C#  

Task task = Thrower();
try
{
     await task;
}
catch (AlexsException)
{
     // Исключение обрабатывается здесь
}
 
← Предыдущая тема
Асинхронное программирование в C# (используем async, await и Task на примере)
 
Следующая тема →
Что такое Домены приложений в C# ? (класс AppDomain)
 
Ваши Отзывы ... 1 комментариев
Михаил
3 июня 2022 17:17
"Оно включается в сигнатуру метода точно так же, как, например, слово static."
Мне кажется это не совсем так, ведь сигнатура в интерфейсах не включает в себя async, и все равно работает как надо
   
Вашe имя
Ваш комментарий (www ссылки может добавлять только залогиненный пользователь)

  Объявления  
  Объявления  
 
Загрузка и установка Microsoft Visual Studio
Скачать и установить Visual Studio 2022 (для изучения C#, написание программ: WPF, ASP.NET, ASP.NET Core, UWP, Miaui, Xamarin, Unity, MonoGame)
Скачать и установить Visual Studio 2019 (для изучения C#, написание программ: WPF, ASP.NET, ASP.NET Core, Xamarin, Unity, MonoGame)
Загрузка и установка Visual Studio 2017 (для изучения C#, написание программ: WPF, ASP.NET, ASP.NET Core, Xamarin, Unity, MonoGame)
Новое приложение для изучения C#
Создаем новое консольное приложение для изучения C#
Отладка кода
Debug.Assert(false) Отладка кода в C#
Для отладки, опция "Common Language Runtime Exceptions" увидеть исключения, когда выполняется программа C#
Атрибут [Obsolete("Мой метод устарел. Не используйте", false)] Предупреждение при компиляции кода в C#
Типы данных C#
C# типы данных: число (bool, char, byte, int, long, float, double, decimal), текст (string), перечисление (enum), класс (class), структура (struct)
Структура Boolean В C# это флаг со значениями true или false (bool) и методы для конвертации bool
Структура Int32 В C# это целое число со знаком (int) и методы для конвертации int
Структура Single В C# это число с плавающей запятой (float) и методы для конвертации float
var ... Переменная любого типа В C#. Пример: var str = "Hello!";
Тип dynamic В C#
Значения по умолчанию В C#
Хранение объектов в памяти. Удаление объектов из памяти
Ссылочные типы и типы значений В C#
Стэк (stack) - память для параметров метода и локальных переменных В C#
Heap - динамическая память доступная во время выполнения программы В C#
Интерфейс IDisposable. Пишем код для правильного освобождения неуправляемых ресурсов в деструкторе и в интерфейсе IDisposable В C#
Память. Сборщик мусора (garbage collector). Автоматическое освобождение памяти В C#
C# конвертация типов
C# конвертация строки в число (string → short, int, long, ushort, uint, ulong, float, double, decimal) | используем Culture (настройки системы)
C# конвертация числа в строку (int, double, short, ... → string) с требуемой точностью
Текст в C# (тип string и класс String)
Алгоритм пересечения прямоугольников
Что такое текст В C# ? Тип string и класс String. Методы для работы с текстом.
Length (длина строки в C#). Пример: string str1 = "Hello"; int v1 = str1.Length;
CompareTo (сравнивает текст с учетом регистра в C#). Пример: bool bIsSame = str1.CompareTo(str2)==0;
ToLower (конвертирует текст в нижний регистр в C#). Пример: string str1 = "HELLO World!"; string str2 = str1.ToLower();
ToUpper (конвертирует текст в верхний регистр в C#). Пример: string str1 = "Hello World!"; string str2 = str1.ToUpper();
Split (разбить строку на слова в C#). Пример: string[] arrWords = strText.Split(' ');
StartsWith (проверяет начало текста с указанным текстом с учетом регистра в C#). Пример: bool bStart = str1.StartsWith(str2);
Contains (проверяет содержит текст указанный текст или нет с учетом регистра в C#). Пример: bool bFound = str1.Contains(str2);
IndexOf (ищет строку с учетом регистра и возвращает позицию в C#). Пример: int pos = str1.IndexOf(str2);
Substring (возвращает часть текста с указанной позиции и длиной В C#). Пример: string str1 = "Hello World!"; string str2 = str1.Substring(2, 5);
IsNullOrEmpty (проверяет текст на пустой или на null В C#). Пример: string name = "Hello World!"; bool bFlag = String.IsNullOrEmpty(name);
IsNullOrWhiteSpace (проверяет текст на null или на текст с пробелами В C#). Пример: string name = "   "; bool bFlag = String.IsNullOrWhiteSpace(name);
[] (возвращает символ с указанной позиции В C#). Пример: char symbol = str[1];
Format (форматирование текста, строки В C#). Пример: string strNew = String.Format("Hello {0}, {1}", name, year);
+ (добавление строк и текста В C#). Пример: string str = str1 + str2 + " people!";
$ (интерполяция строк В C#). Пример: string result = $"Hello {a} + {b} = {a + b}";
Символ @ перед началом строки В C#. Пример: string str1 = @"aaa";
Используем вместе @ и $ (интерполяцию строк в C#)
DateTime (дата и время) в C#
Что такое DateTime в C# ? Конвертация в строку с форматом
Перечисления в C# (enum)
Что такое перечисление (enum) В C# ?
Как преобразовать текст в enum в C#
Как перечислить все элементы в enum в C#
null
null значение для простых типов. Используем ? или Nullable В C#
Оператор ?? (null-объединение) В C#
try-catch
Обработка исключений в C#. Оператор try catch finally
Классы в C# (class)
Что такое класс В C#?
Модификаторы доступа класса В C#. Модификаторы доступа для методов, свойств, полей В C#
'partial class' В C#. Описание класса в разных файлах
Конструкторы для класса
Конструктор класса В C#
Инициализация объекта класса (установка значений для полей) В C#
Вызов конструктора у базового класса В C#
Статический конструктор в классе C#
'base' Для вызова метода из базового класса. Для вызова переменной из базового класса. Для вызова конструктора из базового класса. C#
'this' Для установки или получения значения у поля класса. Для вызова конструктора из класса. C#
Деструкторы для класса
Деструктор класса В C#
Деструкторы в классах (как вызываются базовые деструкторы) C#
Наследование
Что такое наследование класса в C# ?
Наследование с использованием new
Используем new для метода интерфейса. Наследование интерфейса от интерфейса с одинаковым методом
Используем new для метода класса. Наследование класса от класса в C#.
Наследование с использованием sealed
sealed class. Запрет наследоваться В C#
Наследование класса от класса в C#. Используем слова virtual, override, sealed для методов класса
Абстрактный класс
Что такое абстрактный класс В C# ? Абстрактные методы, свойства, индексы.
Наследование от класса abstract В C#. Используем abstract и override для методов класса
Константы и readonly поля в классе
Константы в классе C#
readonly . Для поля класса. Это поле только для чтения в C#
Свойства get и set в классе C# (аксессоры)
get set Свойства в классе C#
Наследование (virtual, override) для аксессоров get и set в C#
Операторы, индексаторы в C#
Операторы в классе C#. Перегрузка операторов: > < ++ + true false
Индексаторы в классе C#
Вложенные типы в C#
Вложенный класс, структура в C#
Параметры в методе класса C#
ref и out (возврат параметров по ссылке в методе) C#. Пример: public void AddValue(ref int value)
Параметры по умолчанию (необязательные параметры) в методе C#. Пример: public int CalculateSum(int a, int b, int c=7)
Именованные параметры C#. Пример: public void CalculateSum(a:7, b:3);
Универсальные методы, универсальные классы в C# (шаблоны)
Метод с универсальными параметрами в C# (шаблоны). Пример: public double Sum<T1, T2>(T1 value1, T2 value2) { ... }
Обобщенный (типизированный) класс в C# (шаблоны). Пример class Book<T> { ... }
where Ограничение типа в обобщенном (типизированном) классе в C# (шаблоны). Пример class Dog<T> where T : Cat
Преобразование объекта класса из одного типа в другой
explicit это явный оператор преобразования в классе C#
implicit это неявный оператор преобразования в классе C#
Преобразование объекта класса из одного типа в другой в C#. Используем try ( ) is as
Преобразование объекта класса из одного типа в другой в C#. Используем pattern matching is switch
Объект класса в C#
? оператор условного null в C#
Объект класса содержит ссылку в C#
Как чтобы при копировании объектов в C# копировались данные класса, а не ссылка?
Статический конструктор и статические свойства и методы
Статический конструктор в классе C#
Статические методы, свойства, члены в классе C#
Дополнительные возможности класса в C#
Метод расширения в C# (this в первом параметре метода). Пример: static public void AddValues(this List<int> myList, int value1, int value2)
Правила именования классов в C#
Какими буквами строчными или заглавными называть классы, методы, свойства ... в C#
Правильно ли для каждого класса в C# создавать свой .cs файл? Или писать классы C# в одном .cs файле?
Статический класс
Статический класс в C#
Анонимный класс
Объект с анонимным (отсутствующим) типом в C#. Пример: var book = new { BookName = "Властелин Колец", Price = 100 };
Интерфейсы
Что такое interface в C# ?
Наследование interface от interface в C#
Наследование класса от класса от interface в C#. Используем override и virtual для методов класса
Обобщенный (типизированный) интерфейс в C# (шаблоны). Пример interface IUser<T> { ... }
Структура struct
Что такое структура в C#?
Модификаторы доступа структуры в C#. Модификаторы доступа для методов, свойств, полей структуры в C#
Инициализация объекта структуры (установка значений для полей) в C#
Как поменять значение в массиве структур или в коллекции структур (List) в C#
Вложенная структура в C#
Преобразование объекта структуры из одного типа в другой
implicit это неявный оператор преобразования структуры в C#
explicit это явный оператор преобразования структуры в C#
Отложенная загрузка class Lazy в C#
Отложенное создание объекта в памяти (class Lazy в C#)
Кортежи (tuple)
Кортежи (tuple) в C#
Динамические объекты с любыми свойствами
DynamicObject и ExpandoObject в C#
Массивы
Что такое массивы? array в C#
Инициализация массива (заполнение элементов массива array) в C#
params передача любого количества параметров в метод в C#
Класс Array (для работы с массивом) C#
Коллекции
Что такое коллекции в C# ?
Что такое необобщенные коллекции в C# ? Классы ArrayList, Stack, Queue, Hashtable, SortedList, BitArray
Что такое обобщенные (типизированные) коллекции в C# ? Классы List<T>, SortedList<T>, Stack<T>, Dictionary<TKey,TValue>, LinkedList<T>, Queue<T>, HashSet<T>, SortedSet<T>, ConcurrentDictionary<TKey, TValue>, SortedDictionary<TKey, TValue>
Классы необобщенных коллекций (в одной коллекции хранятся элементы разного типа)
Интерфейс IEnumerable. Самый базовый интерфейс для коллекций в C#
Интерфейсы: ICollection, IList, IDictionary. Основа для коллекций в C#
Класс ArrayList (коллекция в C#)
Что такое ArrayList в C# ?
Класс SortedList (коллекция в C#)
Что такое SortedList в C# ?
Класс Stack (коллекция в C#)
Что такое Stack в C# ?
Класс Queue (коллекция в C#)
Что такое Queue в C# ?
Класс Hashtable (коллекция в C#)
Что такое Hashtable в C# ?
Класс BitArray (коллекция в C#)
Что такое BitArray в C# ?
Классы обобщенных, типизированных коллекций в C# (в одной коллекции хранятся элементы одного типа)
Интерфейс IEnumerable<T>. Самый базовый интерфейс для типизированных коллекций в C#
Интерфейсы: ICollection<T>, IList<T>, ISet<T>, IDictionary<TKey, TValue>. Основа для типизированных коллекций в C#
Класс List<T> (типизированная коллекция в C#)
Что такое List<T> в C# ?
Инициализация коллекции List в фигурных скобках В C#
for, foreach (проходим все элементы в List<T>) в C#
Find (ищем элемент по критерию в List<T>) в C#
FindAll (ищем список элементов по критерию в List<T>) в C#
ForEach (для каждого элемента List<T> выполняется действие) в C#
Класс LinkedList<T> (типизированная коллекция в C#)
Что такое LinkedList<T> в C# ?
Класс SortedList<TKey, TValue> (типизированная коллекция в C#)
Что такое SortedList<TKey, TValue> в C# ?
Класс Stack<T> (типизированная коллекция в C#)
Что такое Stack<T> в C# ?
Класс Queue<T> (типизированная коллекция в C#)
Что такое Queue<T> в C# ?
Класс HashSet<T> (типизированная коллекция в C#)
Что такое HashSet<T> в C# ?
Как устроен HashSet<T> в C#
Класс SortedSet<T> (типизированная коллекция в C#)
Что такое SortedSet<T> в C# ?
Класс ObservableCollection<T> (типизированная коллекция в C#)
Что такое ObservableCollection<T> в C# ?
Класс Dictionary<TKey, TValue> (типизированная коллекция в C#)
Что такое Dictionary<TKey, TValue> в C# ?
Инициализация элементов в конструкторе Dictionary<TKey, TValue> в C#
Как устроен Dictionary<TKey, TValue> в C#
Как в C# сконвертировать IEnumerable в → Dictionary<TKey, TValue> . Используем метод ToDictionary
Класс SortedDictionary<TKey, TValue> (типизированная коллекция в C#)
Что такое SortedDictionary<TKey, TValue> в C# ?
Класс ConcurrentDictionary<TKey, TValue> (типизированная коллекция в C#)
Что такое ConcurrentDictionary<TKey, TValue> в C# ?
AddOrUpdate (добавить или обновить значение по ключу в ConcurrentDictionary<TKey, TValue>) в C#
Асимптотическая сложность для добавления, удаления, взятия элемента в коллекциях
Асимптотическая сложность для добавления, удаления, взятия элемента в коллекциях C# (List, SortedList, Stack, Dictionary, LinkedList, Queue, HashSet, SortedSet, ConcurrentDictionary, SortedDictionary)
Сортировка элементов в массиве [] и коллекции List
Сортировка элементов в массиве [] и коллекции List<T> в C#. Интерфейс IComparable
Сортировка элементов в массиве [] и коллекции List<T> в C#. Интерфейс IComparer
Моя реализация IEnumerator, IEnumerable и итераторы
Пример: Моя реализация интерфейсов IEnumerable и IEnumerator в C#
Итераторы и yield в C#. Примеры реализации IEnumerable с помощью yield
Методы расширения для IEnumerable (поиск, замена, выборка значений) в C#
Методы поиска, замены, выборки значений в IEnumerable<T>. Методы расширений для IEnumerable<T> в C#
Any (метод расширения IEnumerable<T>) в C#
Select (метод расширения IEnumerable<T>) в C#
GroupBy (метод расширения IEnumerable<T>) В C#
GroupJoin (метод расширения IEnumerable<T>) В C#
Сортировка, фильтрация в LINQ (Language-Integrated Query)
Что такое LINQ в C# ?
Сортировка, фильтрация элементов списка с помощью LINQ в C#
Книги для изучения LINQ в C#
Указатели
Указатели в C#. Оператор unsafe
Указатели на структуры, поля классов, массивы в C# . Операторы unsafe, stackalloc, fixed
Работа с файлами
Открываем файл, читаем текст из файла и разбиваем по словам. C#
Создаем текстовый файл, пишем текст в файл C#
Создаем HTML файл, пишем табличные данные в HTML файл | C#
Создаем бинарный файл, пишем байты в файл C#
Частичная загрузка файла с FTP в C#
Класс Path. Метод Combine - объединяет строки в полный путь файла. И другие методы класса Path | C#
Сериализация
Что такое сериализация объекта в C# ? Атрибут [Serializable]
Сериализация C# объекта в бинарный файл. Класс BinaryFormatter. Атрибут [Serializable]
Сериализация C# объекта в XML файл. Класс XmlSerializer. Атрибут [Serializable]
Сериализация C# объекта в JSON файл. Класс DataContractJsonSerializer. Атрибут [Serializable]
Сериализация C# объекта в SOAP файл. Класс SoapFormatter. Атрибут [Serializable]
Пространства имен
Пространства имен namespace using в C#
Delegate
Делегат (delegate) в C#
Добавление метода(методов) в делегате C#. Объединение делегатов. Удаление метода из делегата
Делегат как параметр в методе C#
Безымянный, анонимный метод в C# (метод описанный на месте параметра, делегата)
Универсальные делегаты
Универсальные, обобщенные делегаты в C# (шаблоны)
Универсальные делегаты Action, Predicate и Func в C#
События
События (event) в C#
Лямда
Лямда (пример) в C#
Регулярные выражения
Регулярные выражения в C#
Разбиваем текст на слова (регулярные выражения в c#)
Ставим * вместо фамилии после первой буквы (регулярные выражения в c#)
Разбиваем текст на слова (регулярные выражения в c#)
Процесс, модули процесса
Процесс в C# (класс Process)
Модули процесса в С# (класс ProcessModule)
Потоки, многопоточность
Потоки в C# (класс Thread)
Пул потоков в C# (Thread Pool)
В чем отличие background (фоновый поток) и foreground (на переднем плане поток) в C# ?
Синхронизация потоков в C#
Parallel Library Task (TPL) Параллельное программирование задач
Parallel Library Task (TPL). Библиотека параллельных задач в C#
Класс Parallel используя метод Invoke параллельно выполненяет методы, циклов for и foreach (на разных ядрах процессора) в C#
PLINQ распараллеливает LINQ запросы для выполнения на разных ядрах процессора в C#
Асинхронные методы (async и await)
class Task в C#
Асинхронное программирование в C# (async, await как оформлять)
Асинхронное программирование в C# (используем async, await и Task на примере)
Асинхронное программирование в C# (теория)
Домены приложений
Что такое Домены приложений в C# ? (класс AppDomain)
Пример "Информация о домене приложения" (имя текущего домена, перечисляем сборки) в C#
Пример "Создаем 2-ой домен приложения. Пишем класс в 1-ом домене и используем во 2-ом домене. MarshalByRefObject в C#
Пример "Загружаем 2-ой домен приложения из файла, запускаем вычисления, выгружаем 2-ой домен из памяти" в C#
Атрибуты
Атрибуты для класса, метода, свойства в C#
Атрибут [Conditional("AAA")] . Для компиляции игнорировать метод или свойство если не определен символ условной компиляции в C#
Атрибут [Obsolete("Мой метод устарел. Не используйте", false)] Предупреждение при компиляции кода в C#
Атрибут [Display(Name = "Sleep at night")] . Для хранения какого нибудь текста прикрепленного к переменной | C#
Аттрибут [Required(ErrorMessage = "Пожалуйста, введите название")] описывается для свойства в C# классе и требует чтобы свойство было заполнено, если не заполнено на экране ошибка ErrorMessage в ASP.NET MVC
Аттрибут [Remote("IsValidAuthor", "Home", ErrorMessage = "Enter correct author of book")] описывается для свойства в C# классе и проверяет это свойство на правильность на сервере через метод IsValidAuthor в conroller Home, если метод возвращает false, то на экране будет ошибка ErrorMessage в ASP.NET MVC
Рефлексия (отражение) reflection в C#
Оператор nameof в C# (имя класса, имя метода, имя переменной)
Что такое рефлексия (отражение) в C# ? Класс Type
Создание объекта класса и вызов конструтора с параметрами используя рефлексию (отражение) reflection в C#
Как получить информацию атрибута для метода у класса. Используем reflection (отражение)
Как получить информацию атрибута для свойства у класса. Используем reflection (отражение)
Директивы препроцессора (if при компиляции)
Директивы препроцессора #define #undef #if #elif #else #endif в C#
Как определить #define для всех файлов (для всего проекта) в С# ?
Что такое сборка и исполняющая среда CLR ?
Сборка (Assembly) в C#. Компиляция. Промежуточный код IL (Intermediate Language). Метаданные.
Как подключить C# сборку в проект?
Утилита ildasm.exe. Конвертирует сборку (C# exe, dll файл) в промежуточный язык IL (Intermediate Language). Эта утилита удобна для изучения
Исполняющая среда CLR (Common Language Runtime) в C# . JIT (Just-In-Time) компилятор.
Создание и подключение нашей сборки
Создание нашей C# сборки (обычная сборка)
Подключение нашей C# сборки (обычная сборка)
Создание нашей C# сборки (разделяемая сборка)
Подключение нашей C# сборки (разделяемая сборка)
База данных в консольном приложении C#
Entity Framework в консольном приложении C#. Используем Code First (пишем c# код, а таблицы в базе данных создаются сами)
Читаем картинку из базы данных и сохраняем в файл | ADO.NET, C#, консольное приложение
Внедрение зависимостей (Dependency Injection) DI в C#
Dependency Injection (DI) Внедрение зависимостей в C#
Ninject (IoC-контейнер) управление зависимостями в C#
Autofac (IoC-контейнер) управление зависимостями в C#
Удобные утилиты Visual Studio
Графическая диаграмма классов в C# (View Class Diagram)
exe to C# code
"dotPeek" application for decompile (disassemble) exe to c# source code
В приложении C# вызываем C++ функции
Что такое управляемый код (managed code) и неуправляемый код (unmanaged code) ? | C# и C++
Маршалинг (marshalling) в C#. Преобразование типов между управляемым кодом (managed code) и неуправляемым кодом (unmanaged code)
В приложении C# вызываем функции из Windows dll (C++ WinAPI). Атрибут [DllImport("user32.dll")]
В приложении C# вызываем функции из моей dll (C++). Атрибут [DllImport("My.dll", CallingConvention = CallingConvention.Cdecl)]
Дополнительные темы, вопросы
Не создается новый проект в Visual Studio 2019. Ошибка "Object reference not set to instance of an object"
Ошибка компиляции C#: error CS1106: Extension method must be defined in a non-generic static class
Ошибка компиляции C#: error CS0246: The type or namespace name 'Point' could not be found (are you missing a using directive or an assembly reference?)
Почему метод Dictionary.TryGetValue не может найти значение по ключу в C# ?
Объектно-ориентированное программирование (ООП). Принципы ООП: абстрагирование, инкапсуляция, наследование, полиморфизм
Какими буквами в C# (заглавными или строчными или прописными) называть поля, методы в классе, интерфейсы, делегаты, параметры ?
Правильно ли для каждого класса в C# создавать свой .cs файл? Или писать классы C# в одном .cs файле?
Что лучше использовать встроенный тип int или класс Integer (тип string или класс String) на C#?
Как скачать и установить нужную .NET Framework версию в Visual Studio ?
Упаковка и распаковка значимых типов в C# (boxing/unboxing)
Error CS8107 Feature 'default literal' is not available in C# 7.0. Please use language version 7.1 or greater
Error "unable to connect to web server "iis express" | C# | Visual Studio 2017
Удаляем и устанавливаем NuGet в Visual Studio
При открытии проекта в Visual Studio 2019 ошибка: "project requires 'SQL Server 2012 Express LocalDB' which is not installed on this computer"
Математические операторы checked и unchecked
Математический оператор unchecked в C#
Математический оператор checked в C#
Дополнительный C# классы
C# класс Random
C# структура Point
C# структура PointF
C# структура Size
C# структура SizeF
C# структура Rectangle
C# структура RectangleF
Время
Время, истекшее с момента загрузки системы (в миллисекундах). System.Environment.TickCount в C#
Шифрование / Cryptography
Зашифруем пароль и проверим | C# console application
Excell
Чтение excel файла на C# (сonsole application)
WWW сайты для изучения C#
Сайты для изучения C#

  Ваши вопросы присылайте по почте: info@dir.by  
Яндекс.Метрика