C# Cooking
132 subscribers
42 photos
50 videos
68 links
Просветительский канал по языку C# CSharpCooking.github.io
Download Telegram
Вопрос:
Доступны ли COM-объекты в Linux?
Ответ:
COM (Component Object Model) — это технология, разработанная компанией Microsoft для взаимодействия объектов в рамках одного процесса или между процессами, а также взаимодействия между компьютерами в сети. Эта технология является основой для многих других технологий Microsoft, включая OLE, OLE Automation, Browser Helper Object, ActiveX, COM+, DCOM, Windows Shell, DirectX и многих других.
Все эти технологии являются частью операционной системы Windows, и они не поддерживаются в Linux нативно. Однако, есть несколько подходов, которые позволяют работать с COM-объектами в Linux:
1. Wine — это слой совместимости, позволяющий запускать приложения Windows на различных POSIX-совместимых операционных системах, таких как Linux, macOS и BSD. Он имитирует WinAPI на уровне системных вызовов.
2. Mono — это кросс-платформенная реализация .NET Framework, которая поддерживает большинство функциональных возможностей .NET, и некоторые из них могут использоваться для взаимодействия с COM-объектами.
3. Виртуальные машины или контейнеры (например, Docker с Windows контейнерами) — это еще один подход, который позволяет запускать приложения Windows в Linux.
Обратите внимание, что все эти подходы имеют свои ограничения, и не все COM-объекты могут работать корректно в Linux даже с использованием этих методов.

#программирование #сишарп #csharp
👨‍💻1
Вопрос:
В чем разница между типами int и nint?
Ответ:
Типы int и nint в C# представляют собой целочисленные типы данных, но они имеют несколько различий.
int – это стандартный целочисленный тип данных в C#, который представляет 32-битное знаковое целое число. Он может содержать значения от -2,147,483,648 до 2,147,483,647.
nint, с другой стороны, является новым типом данных, введенным в C# 9.0, и представляет собой целое число размером с указатель. Он предназначен для совместимости с размерами в нативном коде и может быть 32-битным на 32-битных платформах и 64-битным на 64-битных платформах.
Тип nint является частью набора новых типов данных (включая nuint и nfloat), которые предназначены для упрощения работы с нативными API, особенно в контекстах, где размеры данных могут варьироваться в зависимости от платформы.
Важно отметить, что nint и другие нативные целочисленные типы используются в специфических сценариях и не предназначены для общего использования в большинстве приложений C#. Для большинства приложений стандартные числовые типы данных C#, такие как int, long, float, double и т.д., остаются наиболее подходящими.
Типы nint и nuint в C# были введены для упрощения работы с платформозависимыми или нативными API, где размер целочисленных значений может быть разным в зависимости от архитектуры процессора (32-битный или 64-битный). Эти типы представляют целые числа, размер которых соответствует размеру указателя в данной системе.
Большинство приложений C# не имеют непосредственной необходимости в такой платформозависимой функциональности. Стандартные числовые типы, такие как int, long, float, double и т.д., уже предоставляют абстракцию для работы с числами, не зависящую от платформы, и они хорошо подходят для большинства задач.
Использование nint и nuint в общих приложениях может привести к путанице и сложностям в поддержке кода, так как поведение этих типов может меняться в зависимости от платформы. Кроме того, возможно, вам придется столкнуться с вопросами совместимости, если ваши данные переходят между различными архитектурами.
В общем, nint и nuint следует использовать только в тех случаях, когда это действительно необходимо для взаимодействия с нативным кодом или API, которые зависят от размера указателя.

#программирование #сишарп #csharp
👍1
Вопрос:
В чем полезность записей (record)?
Ответ:
Записи (records) в C# — это тип данных, который представляет собой неизменяемый (immutable) тип ссылки и предоставляет функционал семантического сравнения значений. Другими словами, записи предоставляют способ определить типы данных, которые ведут себя больше как значения, чем как объекты.
Вот некоторые преимущества использования записей:
1. Неизменяемость: Записи являются неизменяемыми по умолчанию, что делает их безопасными для использования в многопоточных окружениях и упрощает понимание их поведения.
2. Семантическое сравнение: Записи поддерживают семантическое сравнение значений. Это означает, что две записи с одинаковыми значениями будут считаться равными, даже если они являются разными объектами.
3. Упрощение кода: Записи в C# 9.0 и новее поддерживают синтаксис инициализации, который позволяет легко создавать новые экземпляры записей с измененными значениями. Это также помогает уменьшить количество шаблонного кода, которое необходимо написать.
4. Встроенные методы: Записи автоматически генерируют полезные методы, такие как Equals, GetHashCode, ToString и операторы сравнения, основываясь на свойствах записи.
Вот пример использования записи:
public record Person(string FirstName, string LastName);
В этом примере Person является записью с двумя свойствами: FirstName и LastName. Эти свойства автоматически получают методы get, и их значения устанавливаются при создании объекта Person. Поскольку Person является записью, она также автоматически получает реализации методов Equals, GetHashCode, ToString и операторов сравнения.

#программирование #сишарп #csharp
Вопрос:
Как будет выполняться обработка, если в нижеуказанном коде второму параметру метода Create задать значение false?
int[] numbers = { 3, 4, 5, 6, 7, 8, 9 };
var parallelQuery =
Partitioner.Create(numbers, true).AsParallel()
.Where(n => n%2 ==0).Dump();
Ответ:
Метод Partitioner.Create используется для разделения исходной коллекции на диапазоны, которые могут быть обработаны параллельно. Второй параметр этого метода, loadBalance, определяет, как будет происходить разделение.
Если параметр loadBalance в методе Partitioner.Create установлен в false, система будет статически распределять элементы по потокам. Это означает, что в начале параллельной обработки все элементы данных будут разделены на наборы (или "партиции"), и каждому потоку будет назначен свой набор данных для обработки. Количество партиций обычно соответствует количеству доступных потоков. Статическое разбиение может быть более эффективным, когда время обработки каждого элемента примерно одинаково, поскольку это уменьшает накладные расходы на координацию между потоками. Однако это может быть менее эффективным, если время обработки отдельных элементов сильно варьируется, так как некоторые потоки могут закончить обработку своих элементов раньше других и остаться без работы.
Если параметр loadBalance в методе Partitioner.Create установлен в true, система будет динамически распределять элементы по потокам. Это значит, что вместо того, чтобы разделить все данные на статические партиции заранее, система будет динамически выделять новые элементы для обработки каждому потоку, когда он заканчивает обработку предыдущих элементов. Динамическое распределение может быть более эффективным, когда время обработки отдельных элементов сильно варьируется, поскольку это позволяет лучше балансировать нагрузку между потоками. Однако это также может привести к большему уровню конкуренции между потоками за доступ к данным, что может снизить производительность в некоторых случаях.

#программирование #сишарп #csharp
Вопрос:
Почему собственный конструктор копирования записи (record) не вызывается для нижеуказанного кода?
void Main() 
{
var point3d = new Point3D (2, 3, 4);
Point3D point3d_2 = point3d;
point3d_2.Dump();
}
record Point (double X, double Y);
record Point3D (double X, double Y, double Z) : Point (X, Y)
{
protected Point3D(Point3D other) : base(other)
{
this.X = 2 * other.X;
this.Y = 2 * other.Y;
this.Z = 2 * other.Z;
}
};
Ответ:
В C# записи (records) по умолчанию имеют специальный конструктор копирования, который создается компилятором и гарантирует, что все свойства копируются в новый экземпляр. Ваш пример пытается переопределить это поведение, но это не работает из-за специфики языка.
В данном случае, оператор присваивания Point3D point3d_2 = point3d; не вызывает конструктор копирования, который вы определили. Он использует конструктор копирования, сгенерированный по умолчанию.
Однако, вам не запрещено определить свой собственный конструктор копирования с дополнительной логикой. Просто обратите внимание, что этот конструктор не будет вызываться при использовании оператора присваивания. Вы должны вызывать его явно, если хотите воспользоваться дополнительной логикой.
Вот пример того, как вы можете явно вызвать свой конструктор копирования:
void Main()
{
var point3d = new Point3D (2, 3, 4);
Point3D point3d_2 = new Point3D(point3d);
point3d_2.Dump();
}
record Point (double X, double Y);
record Point3D (double X, double Y, double Z) : Point (X, Y)
{
public Point3D(Point3D other) : base(other)
{
this.X = 2 * other.X;
this.Y = 2 * other.Y;
this.Z = 2 * other.Z;
}
};

#программирование #сишарп #csharp
Вопрос:
В чем назначение деконструктора записи (record)?
Ответ:
В C# деконструкторы (не путать с деструкторами) предназначены для "распаковки" значений из объектов, включая записи (record). Их основное назначение – улучшение читаемости кода, а также возможность быстрого извлечения значений для использования в других частях кода. Деконструктор для записи разбивает объект на его составные части.
Однако стоит помнить, что деконструкторы в записях (или в любом другом типе) не влияют на жизненный цикл объекта или его управление памятью. Они не освобождают ресурсы, как это делают деструкторы или методы Dispose.
Например, если у вас есть запись Point:
public record Point(int X, int Y);
Вы можете использовать деконструктор следующим образом:
var point = new Point(5, 10);
var (x, y) = point; // Используем деконструктор
Console.WriteLine($"X: {x}, Y: {y}"); // Вывод: X: 5, Y: 10
Итак, деконструкторы – это удобный способ улучшения читаемости и структурирования кода, но они не влияют на управление памятью или ресурсами.

#программирование #сишарп #csharp
🔥1
Начиная с версии C# 9, в шаблонах можно применять операции <, >, <= и >=. Еще большее удобство это приносит в switch.

#программирование #сишарп #csharp
Атрибуты информации о вызывающем компоненте полезны для регистрации в журнале, а также для реализации шаблонов, подобных инициированию одиночного события уведомления об изменении всякий раз, когда модифицируется любое свойство объекта. На самом деле для этого в пространстве имен System.ComponentModel предусмотрен стандартный интерфейс по имени INotifyPropertyChanged:
public interface INotifyPropertyChanged 
{
event PropertyChangedEventHandler PropertyChanged;
}
public delegate void PropertyChangedEventHandler
(object sender, PropertyChangedEventArgs e);
public class PropertyChangedEventArgs : EventArgs
{
public PropertyChangedEventArgs(string propertyName);
public virtual string PropertyName { get; }
}
Обратите внимание, что конструктор класса PropertyChangedEventArgs требует имени свойства, значение которого изменяется. Однако за счет применения атрибута [CallerMemberName] мы можем реализовать данный интерфейс и вызвать событие, даже не указывая имена свойств.

#программирование #сишарп
Вопрос:
Можно ли обратиться к несуществующему методу объекта?
Ответ:
Да, это возможно, если применить специальное связывание. Например, в данном коде класс Duck на самом деле не имеет метода Quack. Взамен он применяет специальное связывание для перехвата и интерпретации всех обращений к методам.

#программирование #сишарп #csharp
Вопрос:
В нижеуказанном коде задействован ли планировщик задач, какое число потоков из пула будет задействовано, если число итераций будет значительным?
for (int i = 0; i < basePrime.Length; i++)
{
ThreadPool.QueueUserWorkItem(Run, basePrime[i]);
}
Ответ:
Да, в этом коде используется планировщик задач в виде пула потоков, а именно ThreadPool. Каждый вызов ThreadPool.QueueUserWorkItem ставит в очередь новую задачу для выполнения в пуле потоков. Пул потоков автоматически управляет числом работающих потоков в зависимости от загрузки процессора и других параметров системы. Он может автоматически создавать и удалять потоки, чтобы поддерживать высокую производительность и эффективность системы. В случае большого числа итераций не все задачи будут выполняться сразу. Некоторые из них будут помещены в очередь и ждать освобождения потоков. Но точное число используемых потоков зависит от многих факторов, включая текущую загрузку процессора и настройки операционной системы. Так что нельзя точно сказать, сколько потоков будет задействовано в данном случае. Однако важно отметить, что пул потоков предназначен для управления "быстрыми" операциями, и, если операции занимают значительное время, лучше использовать другие подходы к распараллеливанию.

#программирование #сишарп #csharp
💩1
Вопрос:
Почему Dictionary<int, string> считается закрытым обобщенным типом?
Ответ:
Обобщённый тип (generic type) в C# — это тип, который принимает один или несколько типов в качестве параметров.
Dictionary<TKey, TValue> — это обобщённый тип, он принимает два типа: TKey и TValue. Когда вы заменяете эти параметры типа на конкретные типы, например int и string, вы создаёте экземпляр этого обобщённого типа, который называется закрытым обобщённым типом.
Так, Dictionary<int, string> — это закрытый обобщённый тип, потому что все его параметры типа заменены на конкретные типы.
С другой стороны, если бы у нас был тип Dictionary<int, T>, он был бы частично закрытым, потому что только один из параметров типа заменён на конкретный тип, а другой — нет. Dictionary<T, U> — это открытый обобщённый тип, потому что ни один из его параметров типа не заменён на конкретный тип.

#программирование #сишарп #csharp
Помечая тип, член типа или блок операторов ключевым словом unsafe, вы разрешаете внутри этой области видимости использовать типы указателей и выполнять операции над указателями в стиле C++. На рисунке показан пример применения указателей для быстрой обработки битовой карты.

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

#программирование #сишарп #csharp #csharpdotnet #csharpprogramming
Вопрос:
Как работает механизм двойной буферизации в Windows Form?
Ответ:
Механизм двойной буферизации в Windows Forms используется для предотвращения мерцания при перерисовке элементов на форме. Это достигается путем рисования всего содержимого на скрытом буфере перед тем, как его отображать на экране. Вместо того, чтобы изменения рисовались напрямую на экране, что может вызвать видимые артефакты и мерцание, изменения рисуются сначала во вторичном буфере, а затем весь буфер быстро копируется на экран.
Вот как это работает шаг за шагом:
1. Вместо того, чтобы рисовать прямо на экране, приложение рисует на скрытой поверхности, называемой "вторичным буфером" или "буфером заднего плана" (back buffer).
2. Как только весь кадр готов во вторичном буфере, содержимое буфера быстро копируется на экран.
3. Этот процесс повторяется каждый раз, когда происходит перерисовка формы. Вместо многократного рисования прямо на экране, что может вызывать мерцание, все изменения рисуются сначала на буфере, а затем отображаются за один раз.
В Windows Forms можно включить двойную буферизацию для определенного элемента управления (например, для всей формы) путем установки свойства DoubleBuffered в true:
this.DoubleBuffered = true;
Это говорит Windows Forms использовать двойную буферизацию при отрисовке, что должно снизить или устранить видимое мерцание при динамической перерисовке контента. Однако стоит отметить, что двойная буферизация может увеличить потребление ресурсов, так как требует дополнительной памяти для хранения вторичного буфера.
Если в Windows Forms имеется множество элементов управления, которые нужно рисовать с использованием двойной буферизации, можно включить двойную буферизацию для каждого элемента управления индивидуально и для всей формы в целом. Вот как можно это сделать:
public MyForm()
{
InitializeComponent();
// Включение двойной буферизации для формы
this.DoubleBuffered = true;
// Включение двойной буферизации для всех элементов управления на форме
SetDoubleBuffered(this);
}
private void SetDoubleBuffered(Control control)
{
// Включение двойной буферизации для текущего элемента управления
control.DoubleBuffered = true;
// Рекурсивное включение двойной буферизации для всех дочерних элементов
foreach (Control childControl in control.Controls)
{
SetDoubleBuffered(childControl);
}
}
Также можно использовать стиль WS_EX_COMPOSITED для включения двойной буферизации на уровне окна, что затрагивает форму и все её дочерние элементы управления. Это делается путем переопределения свойства CreateParams вашей формы. Вот пример того, как это можно сделать:
public class MyDoubleBufferedForm : Form
{
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
return cp;
}
}
}
Используя этот подход, вы можете создать форму, которая автоматически использует двойную буферизацию для себя и всех своих дочерних элементов управления. Однако стоит отметить, что использование WS_EX_COMPOSITED может иметь некоторые побочные эффекты и влиять на производительность, поэтому его следует использовать с осторожностью и тестировать, чтобы убедиться, что он подходит для вашего конкретного сценария.

#программирование #сишарп #csharp #csharpdotnet #csharpprogramming
👍1
Вопрос:
Чем отличается C# от Python?
Ответ:
C# и Python – это два популярных языка программирования, но они имеют ряд отличий:
Типизация: C# – язык со строгой типизацией, тогда как Python использует динамическую типизацию. Это означает, что в C# типы переменных должны быть указаны явно и не могут быть изменены после объявления, в то время как в Python типы данных выводятся автоматически и могут изменяться.
Синтаксис: Python известен своим чистым и кратким синтаксисом, который часто использует отступы для структурирования кода. C# имеет более формальный синтаксис, похожий на C++ и Java, и использует фигурные скобки для обозначения блоков кода.
Производительность: C# обычно имеет более высокую производительность по сравнению с Python, особенно в приложениях, где необходимы интенсивные вычисления благодаря тому, что он компилируется в промежуточный байт-код и затем оптимизируется JIT-компилятором.
Платформы и экосистемы: C# тесно интегрирован с платформой .NET и широко используется для разработки Windows-приложений, веб-приложений с использованием ASP.NET и кроссплатформенных мобильных приложений с использованием Xamarin. Python очень популярен в науке о данных, машинном обучении, веб-разработке с использованием фреймворков, таких как Django и Flask, и в автоматизации.
Библиотеки и фреймворки: Python имеет огромное количество библиотек для различных целей, особенно в области науки о данных и машинного обучения. C# также имеет множество библиотек, но они в большей степени сосредоточены на разработке приложений.
Сообщество: сообщество Python традиционно сильно представлено в академических и научных кругах, тогда как C# имеет сильное присутствие в промышленном секторе и среди разработчиков корпоративного программного обеспечения.
Управление памятью: C# использует автоматическое управление памятью с помощью сборщика мусора, как и Python. Однако, C# предоставляет более гибкие возможности для управления ресурсами и памятью через использование конструкций, таких как using и явное освобождение ресурсов с помощью интерфейса IDisposable.
Многопоточность: C# предлагает более развитые средства для многопоточной обработки и параллельного программирования через Task Parallel Library (TPL) и асинхронные методы. В Python, из-за глобальной блокировки интерпретатора (GIL), истинное параллельное выполнение потоков является более сложной задачей, хотя он поддерживает многопроцессорность и асинхронное программирование.
Ошибка и исключения: C# требует явной обработки исключений с использованием конструкции try-catch, тогда как Python позволяет опускать обработку исключений (хотя это считается плохой практикой).
Инструменты разработки: C# тесно интегрирован с Visual Studio, которая является одной из наиболее мощных сред разработки. Python, с другой стороны, можно разрабатывать в различных редакторах кода и IDE, таких как PyCharm, Jupyter Notebooks и Visual Studio Code.
Интероперабельность: C# легко взаимодействует с другими технологиями и языками в экосистеме .NET. Python является более скриптовым языком и может быть использован для автоматизации множества систем и приложений, но может иметь ограничения в интеграции с некоторыми платформами.
В зависимости от контекста и требований проекта, выбор между C# и Python может быть обусловлен различными факторами, такими как производительность, экосистема, предпочтения в синтаксисе и доступные библиотеки.

#программирование #сишарп #csharp #csharpdotnet #csharpprogramming
Вопрос:
Вызов метода GetTypes на многомодульной сборке возвращает все типы из всех модулей . Что понимается под многомодульной сборкой?
Ответ:
Многомодульная сборка в .NET представляет собой сборку, состоящую из нескольких модулей. В контексте .NET, модуль – это единица компиляции, которая может содержать код и метаданные. Модуль похож на сборку, но не может быть развернут самостоятельно; вместо этого он должен существовать внутри сборки. Одномодульные сборки (что является наиболее общим случаем) содержат один модуль, который совпадает с самой сборкой. В многомодульных сборках содержится несколько модулей, объединенных в одну сборку. Создание многомодульных сборок редко используется, но может быть полезным, например, когда вы хотите объединить код, написанный на разных языках программирования, в одну сборку или когда вы хотите разделить большую сборку на более мелкие модули для улучшения управления кодом. Вот пример того, как можно создать многомодульную сборку с использованием компилятора командной строки C# (csc):
# Компилируем первый модуль (без создания сборки)
csc /target:module Module1.cs
# Компилируем второй модуль (без создания сборки)
csc /target:module Module2.cs
# Создаем многомодульную сборку, включающую оба модуля
csc /target:library /out:MultiModuleAssembly.dll /addmodule:Module1.netmodule;Module2.netmodule
При использовании метода GetTypes на многомодульной сборке, метод вернет все типы, определенные во всех модулях, включенных в эту сборку.
Когда говорится, что модуль не может быть развернут самостоятельно, это означает, что он не может существовать как независимая единица развертывания, которую можно было бы загрузить и выполнить непосредственно в среде исполнения .NET. Модули (с расширением .netmodule) содержат скомпилированный код и метаданные, но не содержат сборочную информацию, которая необходима среде исполнения для идентификации, версионности и разрешения зависимостей. Эта информация содержится только на уровне сборки. Сборка, с другой стороны, является единицей развертывания в .NET и содержит всю необходимую информацию для загрузки и выполнения кода средой исполнения. Сборка может содержать один или несколько модулей, и хотя каждый модуль может содержать код, только сборка предоставляет контекст, необходимый для того, чтобы этот код мог быть выполнен. В обычной практике разработчики чаще всего работают с одномодульными сборками, где вся сборка состоит из одного модуля. Многомодульные сборки используются реже и обычно применяются в специализированных сценариях.

#программирование #сишарп #csharp #csharpdotnet #csharpprogramming
Вопрос:
Как задействовать статическое событие TaskScheduler.UnobservedTaskException в сценарии использования задач с необработанными исключениями?
Ответ:
Необработанные исключения в автономных задачах называются необнаруженными исключениями, и среда CLR будет повторно генерировать исключение в потоке финализаторов, когда объект задачи покидает область видимости и обрабатывается сборщиком мусора). TaskScheduler.UnobservedTaskException – это событие, которое срабатывает, когда задача, завершившаяся с исключением, была собрана сборщиком мусора, не будучи обработанной. Это может быть полезно для перехвата и обработки исключений, которые не были явно обработаны в коде.
Ниже пример, который показывает, как можно использовать TaskScheduler.UnobservedTaskException в сценарии с задачами:
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main()
{
// Подписка на событие UnobservedTaskException
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
Console.WriteLine("Необработанное исключение в задаче:");
e.SetObserved(); // Помечаем исключение как обработанное
foreach (var ex in e.Exception.InnerExceptions)
{
Console.WriteLine(" - " + ex.Message);
}
};
// Создание задачи, которая завершается с исключением
var task = Task.Run(() =>
{
throw new Exception("Исключение в задаче");
});
// Задача-продолжение, которая также генерирует исключение
var continuation = task.ContinueWith(t =>
{
throw new Exception("Исключение в продолжении задачи");
});
// Ждем некоторое время, чтобы задачи завершились
Thread.Sleep(1000);
// Выполнение сборки мусора для того, чтобы событие UnobservedTaskException сработало
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Завершение программы.");
}
}
В этом примере создаются две задачи, обе из которых генерируют исключения. Затем явно вызывается сборка мусора (GC.Collect и GC.WaitForPendingFinalizers), чтобы поток финализаторов вызвал событие TaskScheduler.UnobservedTaskException для исключений, которые не были обработаны.
Для справки:
- Метод GC.Collect явно инициирует процесс сборки мусора. Это означает, что сборщик мусора пытается освободить память, удаляя объекты, которые больше не доступны (т.е. на которые нет ссылок). Обычно не рекомендуется вызывать этот метод вручную, потому что сборщик мусора в .NET достаточно эффективен и оптимизирован для работы в различных сценариях. Однако, в некоторых специальных случаях, когда вы точно знаете, что это может быть полезно (например, перед большими вычислениями), можно использовать явное взаимодействие со сборщиком мусора.
- Метод GC.WaitForPendingFinalizers приостанавливает выполнение текущего потока до тех пор, пока сборщик мусора не завершит выполнение всех финализаторов. Финализатор – это специальный метод, который выполняется перед уничтожением объекта, и обычно используется для освобождения неуправляемых ресурсов. Этот вызов полезен в сценариях, где вам необходимо убедиться, что все финализируемые объекты были очищены перед продолжением выполнения кода. Как и с GC.Collect, это не что-то, что следует делать часто, и должно использоваться с осторожностью.

#программирование #сишарп #csharp #csharpdotnet #csharpprogramming
Мощная особенность продолжений связана с тем, что они запускаются, только когда завершены все дочерние задачи. В этой точке любые исключения, сгенерированные дочерними задачами, маршализируются в продолжение.

В примере на слайде мы начинаем три дочерние задачи, каждая из которых генерирует исключение NullReferenceException. Затем мы перехватываем все исключения сразу через продолжение на родительской задаче.

#программирование #сишарп #csharp #csharpdotnet #csharpprogramming
Расширяющий метод “поглощает” необработанные исключения задачи. Метод может быть улучшен добавлением кода для регистрации исключения.

#программирование #сишарп #csharp #csharpdotnet #csharpprogramming
This media is not supported in your browser
VIEW IN TELEGRAM
Параллелизм задач. Расширяющий метод, продолжение и дочерние задачи.

#программирование #сишарп #csharp #csharpdotnet #csharpprogramming