Многопоточность может повысить производительность в приложениях Windows Presentation Foundation (WPF), Universal Windows Platform (UWP) и Windows Forms, но доступ к элементам управления не является потокобезопасным. Не потокобезопасный код может стать причиной для серьезных и сложных ошибок. Два или более потока, оказывающих влияние на элемент управления, могут привести к нестабильному состоянию приложения и вызвать условия состязаний. Данный пост посвящен раскрытию темы вызова элементов управления пользовательского интерфейса потокобезопасным образом, в частности объяснению понятия “контекст синхронизации”.
https://csharpcooking.github.io/2023/02/18/Thread-Safe-Control-Calls.html
#программирование #сишарп #csharp
https://csharpcooking.github.io/2023/02/18/Thread-Safe-Control-Calls.html
#программирование #сишарп #csharp
CSharpCooking
Потокобезопасные вызовы элементов управления в приложениях WPF, UWP и Windows Forms
Многопоточность может повысить производительность в приложениях Windows Presentation Foundation (WPF), Universal Windows Platform (UWP) и Windows Forms, но доступ к элементам управления не является потокобезопасным. Не потокобезопасный код может стать причиной…
Media is too big
VIEW IN TELEGRAM
Создание и запуск задач. TaskCreationOptions и дочерние задачи.
📌 CSharpCooking.github.io/2022/02/27/Task-Scheduler.html
#программирование #сишарп #csharp
📌 CSharpCooking.github.io/2022/02/27/Task-Scheduler.html
#программирование #сишарп #csharp
Преимущества параллельного программирования: увеличение производительности, распределение нагрузки, обработка больших объемов данных, улучшение отзывчивости и др. Однако параллельное программирование также может иметь свои сложности, связанные с управлением синхронизацией, гонками данных и другими аспектами, которые требуют дополнительного внимания и опыта со стороны программиста. В ходе тестирования параллельных программ можно получить неоднозначные результаты. Например, это может происходить, когда мы оптимизируем объединение данных типа float или double посредством методов For или ForEach класса Parallel. Подобное поведение программы заставляет усомниться в потокобезопасности написанного кода. Пост раскрывает возможную причину неоднозначности результатов, получаемых параллельной программой, и предлагает лаконичное решение вопроса.
https://csharpcooking.github.io/2023/03/22/Ambiguous-Results-when-Using-Parallel-Class-Methods-within-the-NET-Framework-Runtime.html
#программирование #сишарп #csharp
https://csharpcooking.github.io/2023/03/22/Ambiguous-Results-when-Using-Parallel-Class-Methods-within-the-NET-Framework-Runtime.html
#программирование #сишарп #csharp
Вопрос:
Доступны ли 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
Доступны ли 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
В чем разница между типами 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 и операторы сравнения, основываясь на свойствах записи.
Вот пример использования записи:
#программирование #сишарп #csharp
В чем полезность записей (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?
Метод Partitioner.Create используется для разделения исходной коллекции на диапазоны, которые могут быть обработаны параллельно. Второй параметр этого метода, loadBalance, определяет, как будет происходить разделение.
Если параметр loadBalance в методе Partitioner.Create установлен в false, система будет статически распределять элементы по потокам. Это означает, что в начале параллельной обработки все элементы данных будут разделены на наборы (или "партиции"), и каждому потоку будет назначен свой набор данных для обработки. Количество партиций обычно соответствует количеству доступных потоков. Статическое разбиение может быть более эффективным, когда время обработки каждого элемента примерно одинаково, поскольку это уменьшает накладные расходы на координацию между потоками. Однако это может быть менее эффективным, если время обработки отдельных элементов сильно варьируется, так как некоторые потоки могут закончить обработку своих элементов раньше других и остаться без работы.
Если параметр loadBalance в методе Partitioner.Create установлен в true, система будет динамически распределять элементы по потокам. Это значит, что вместо того, чтобы разделить все данные на статические партиции заранее, система будет динамически выделять новые элементы для обработки каждому потоку, когда он заканчивает обработку предыдущих элементов. Динамическое распределение может быть более эффективным, когда время обработки отдельных элементов сильно варьируется, поскольку это позволяет лучше балансировать нагрузку между потоками. Однако это также может привести к большему уровню конкуренции между потоками за доступ к данным, что может снизить производительность в некоторых случаях.
#программирование #сишарп #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) не вызывается для нижеуказанного кода?
В C# записи (records) по умолчанию имеют специальный конструктор копирования, который создается компилятором и гарантирует, что все свойства копируются в новый экземпляр. Ваш пример пытается переопределить это поведение, но это не работает из-за специфики языка.
В данном случае, оператор присваивания Point3D point3d_2 = point3d; не вызывает конструктор копирования, который вы определили. Он использует конструктор копирования, сгенерированный по умолчанию.
Однако, вам не запрещено определить свой собственный конструктор копирования с дополнительной логикой. Просто обратите внимание, что этот конструктор не будет вызываться при использовании оператора присваивания. Вы должны вызывать его явно, если хотите воспользоваться дополнительной логикой.
Вот пример того, как вы можете явно вызвать свой конструктор копирования:
Почему собственный конструктор копирования записи (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:
#программирование #сишарп #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
#программирование #сишарп #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]
мы можем реализовать данный интерфейс и вызвать событие, даже не указывая имена свойств.#программирование #сишарп
Вопрос:
Можно ли обратиться к несуществующему методу объекта?
Ответ:
Да, это возможно, если применить специальное связывание. Например, в данном коде класс
#программирование #сишарп #csharp
Можно ли обратиться к несуществующему методу объекта?
Ответ:
Да, это возможно, если применить специальное связывание. Например, в данном коде класс
Duck
на самом деле не имеет метода Quack
. Взамен он применяет специальное связывание для перехвата и интерпретации всех обращений к методам.#программирование #сишарп #csharp
Вопрос:
В нижеуказанном коде задействован ли планировщик задач, какое число потоков из пула будет задействовано, если число итераций будет значительным?
Да, в этом коде используется планировщик задач в виде пула потоков, а именно
#программирование #сишарп #csharp
В нижеуказанном коде задействован ли планировщик задач, какое число потоков из пула будет задействовано, если число итераций будет значительным?
for (int i = 0; i < basePrime.Length; i++)
{
ThreadPool.QueueUserWorkItem(Run, basePrime[i]);
}
Ответ:Да, в этом коде используется планировщик задач в виде пула потоков, а именно
ThreadPool
. Каждый вызов ThreadPool.QueueUserWorkItem
ставит в очередь новую задачу для выполнения в пуле потоков. Пул потоков автоматически управляет числом работающих потоков в зависимости от загрузки процессора и других параметров системы. Он может автоматически создавать и удалять потоки, чтобы поддерживать высокую производительность и эффективность системы. В случае большого числа итераций не все задачи будут выполняться сразу. Некоторые из них будут помещены в очередь и ждать освобождения потоков. Но точное число используемых потоков зависит от многих факторов, включая текущую загрузку процессора и настройки операционной системы. Так что нельзя точно сказать, сколько потоков будет задействовано в данном случае. Однако важно отметить, что пул потоков предназначен для управления "быстрыми" операциями, и, если операции занимают значительное время, лучше использовать другие подходы к распараллеливанию.#программирование #сишарп #csharp
💩1
Вопрос:
Почему
Ответ:
Обобщённый тип (generic type) в C# — это тип, который принимает один или несколько типов в качестве параметров.
Так,
С другой стороны, если бы у нас был тип
#программирование #сишарп #csharp
Почему
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
Небезопасный код может выполняться быстрее, чем соответствующая ему безопасная реализация. В последнем случае код потребует вложенного цикла с индексацией в массиве и проверкой границ. Небезопасный метод C# может также оказаться быстрее, чем вызов внешней функции С, поскольку не будет никаких накладных расходов, связанных с покиданием управляемой среды выполнения.
#программирование #сишарп #csharp #csharpdotnet #csharpprogramming