C# | Вопросы собесов
5.01K subscribers
39 photos
1 file
1.54K links
Сайт: https://easyoffer.ru/
Все каналы: t.me/+xGeAw6ckJ4liYzQy

Контакт для рекламы: @sendme_ads
Download Telegram
🤔 Все ли HTTP-методы идемпотентные?

Нет.
Вот классификация:
Идемпотентные:
- GET — многократный вызов не меняет состояние.
- PUT — задаёт конкретное состояние ресурса.
- DELETE — может быть вызван многократно с тем же результатом.
- HEAD, OPTIONS — тоже идемпотентны.
Неидемпотентные:
- POST — каждый вызов может создавать новый ресурс или изменять состояние (непредсказуемо).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
💊2
🤔 Что такое инверсия зависимостей?

Инверсия зависимостей — это принцип SOLID, который говорит:
> Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.

Это значит, что вместо жёстких зависимостей на конкретные классы, код должен работать через абстракции (interface или abstract class).

🚩Проблема без инверсии зависимостей
Допустим, у нас есть класс EmailSender, который отправляет письма:
public class EmailSender
{
public void Send(string message)
{
Console.WriteLine($"Отправка email: {message}");
}
}

public class NotificationService
{
private EmailSender _emailSender = new EmailSender();

public void Notify(string message)
{
_emailSender.Send(message);
}
}


🚩Решение: Инверсия зависимостей

Чтобы избавиться от жёсткой зависимости, вводим абстракцию (IMessageSender):
public interface IMessageSender
{
void Send(string message);
}

public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine($"Отправка email: {message}");
}
}

public class SmsSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine($"Отправка SMS: {message}");
}
}


Теперь NotificationService зависит не от конкретного класса, а от интерфейса:
public class NotificationService
{
private readonly IMessageSender _messageSender;

public NotificationService(IMessageSender messageSender)
{
_messageSender = messageSender;
}

public void Notify(string message)
{
_messageSender.Send(message);
}
}


Теперь мы можем подставлять любую реализацию IMessageSender:
var emailNotifier = new NotificationService(new EmailSender());
emailNotifier.Notify("Привет через Email!");

var smsNotifier = new NotificationService(new SmsSender());
smsNotifier.Notify("Привет через SMS!");


Вывод
Отправка email: Привет через Email!
Отправка SMS: Привет через SMS!


🚩Преимущества инверсии зависимостей

Гибкость – можно легко заменять зависимости.
Тестируемость – можно подставить Mock-объект вместо EmailSender.
Меньше изменений в коде – можно добавить новые способы отправки сообщений без изменения NotificationService.

Ставь 👍 и забирай 📚 Базу знаний
🤔 В чем разница между асинхронностью и многопоточностью?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Может ли абстрактный метод быть вне абстрактного класса?

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

🚩Почему абстрактный метод требует абстрактного класса?

Абстрактный метод — это метод, который объявлен, но не имеет реализации. Он выступает как "контракт", который обязан быть реализован в производном классе.
public abstract class Shape
{
public abstract double CalculateArea();
}


Абстрактные методы имеют следующие особенности:
Они не могут содержать тело (реализацию).
Их цель — заставить производные классы реализовать конкретную функциональность.
Они всегда принадлежат абстрактным классам.

🚩Пример ошибки

Если попытаться объявить абстрактный метод в обычном классе, компилятор выдаст ошибку
public class RegularClass
{
public abstract void SomeMethod(); // Ошибка: абстрактный метод может быть только в абстрактном классе
}


🚩Логика дизайна

C# требует, чтобы абстрактные методы находились только в абстрактных классах, потому что:
Абстрактные классы могут содержать как абстрактные, так и обычные методы. Это позволяет определять базовое поведение в абстрактном классе и оставлять специфическую реализацию производным классам.
Обычные классы не могут содержать абстрактные методы, так как они предназначены для создания объектов, а объект не может содержать "незавершённый" метод.

Ставь 👍 и забирай 📚 Базу знаний
🤔 В чем разница Redis и Memcached?

Redis — это больше, чем просто кэш: он поддерживает множество структур данных (строки, списки, множества, хэши). Memcached предназначен исключительно для кэширования строк и объектов, проще в использовании. Redis также обеспечивает персистентность данных, чего нет в Memcached.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔1
🤔 Что такое value-type?

Value Type (тип значения) – это тип данных, который хранит своё значение непосредственно в памяти (обычно в стеке), а не ссылку на объект в куче (heap), как это делает ссылочный тип (Reference Type).

🚩Какие типы данных являются Value Type?

Простые типы (int, double, bool, char, byte, float, decimal, etc.)
Структуры (struct)
Перечисления (enum)
Nullable-значения (int?, double?)

🚩Пример Value Type

int a = 10;
int b = a; // Значение копируется

b = 20;
Console.WriteLine(a); // 10 (остался неизменным)
Console.WriteLine(b); // 20


🚩Где хранятся Value Type?

Value Type обычно хранятся в стеке (stack) – это быстрая область памяти.
Если структура (struct) является частью объекта (который хранится в куче), то её значение хранится внутри объекта в куче.
struct Point
{
public int X;
public int Y;
}

class Program
{
static void Main()
{
Point p1 = new Point { X = 5, Y = 10 };
Point p2 = p1; // Копирование структуры (создаётся новый экземпляр)

p2.X = 20;
Console.WriteLine(p1.X); // 5 (остался неизменным)
Console.WriteLine(p2.X); // 20
}
}


🚩Когда использовать Value Type?

Если данные небольшие и часто изменяются – struct
Если объект недолговечный и не требует сложного поведения
Если производительность важна – Value Type быстрее из-за работы в стеке

Ставь 👍 и забирай 📚 Базу знаний
🔥1💊1
🤔 Какие виды связей бывают у join`ов?

Связи бывают: один к одному, один ко многим, многие ко многим. Они определяют, как таблицы взаимодействуют друг с другом через ключи.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
💊1
🤔 Какие типы данных можно использовать у Dictionary в качестве ключа?

В C# ключ (TKey) в Dictionary<TKey, TValue> должен быть уникальным и поддерживать сравнение.
Лучше всего использовать неизменяемые (immutable) типы, такие как:
Примитивные типы (int, string, char, bool, Guid, enum)
Кортежи (Tuple, ValueTuple)
Неизменяемые структуры (struct, если переопределён Equals и GetHashCode)

🚩Какие типы подходят в качестве ключа?

Числовые типы (int, double, long)
var dict = new Dictionary<int, string>
{
{1, "Один"},
{2, "Два"}
};
Console.WriteLine(dict[1]); // Вывод: Один


string (лучший выбор)
var dict = new Dictionary<string, int>
{
{"apple", 10},
{"banana", 5}
};
Console.WriteLine(dict["apple"]); // 10


Guid (уникальные идентификаторы)
var dict = new Dictionary<Guid, string>
{
{Guid.NewGuid(), "User1"},
{Guid.NewGuid(), "User2"}
};


enum (хороший вариант)
enum Status { New, Processing, Completed }

var dict = new Dictionary<Status, string>
{
{Status.New, "Заказ создан"},
{Status.Processing, "Заказ в обработке"}
};


Можно использовать несколько значений в качестве ключа:
var dict = new Dictionary<(int, string), string>
{
{(1, "apple"), "Красное яблоко"},
{(2, "banana"), "Жёлтый банан"}
};
Console.WriteLine(dict[(1, "apple")]); // Красное яблоко


🚩Какие типы нельзя использовать в качестве ключа?

List<T> (и другие изменяемые коллекции)
var dict = new Dictionary<List<int>, string>(); // Ошибка при использовании в качестве ключа!


class, если не переопределён Equals и GetHashCode
class Person { public string Name; }
var dict = new Dictionary<Person, string>(); // Плохо!


Нужно переопределить Equals и GetHashCode
class Person
{
public string Name { get; }

public Person(string name) => Name = name;

public override bool Equals(object? obj)
{
return obj is Person other && Name == other.Name;
}

public override int GetHashCode() => Name.GetHashCode();
}


Ставь 👍 и забирай 📚 Базу знаний
🤔 Какие типы данных можно использовать у Dictionary в качестве ключа?

Ключи должны быть:
- Уникальными
- Иметь устойчивую реализацию GetHashCode() и Equals()
Подходящие типы:
- Примитивы (int, string, GUID и т.п.)
- Структуры (например, кастомные value types)
- Объекты (если правильно переопределены Equals и GetHashCode)


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🔥1
🤔 Какие бывают типы данных?

В C# существует множество различных типов данных, которые можно разделить на две основные категории: значимые типы (value types) и ссылочные типы (reference types). Рассмотрим каждую из этих категорий и их подтипы.

🚩Значимые типы (Value Types)

Значимые типы хранят данные непосредственно в своей памяти. Они обычно располагаются в стеке и имеют фиксированный размер. К значимым типам относятся:

🟠Простые типы (Simple Types)
Числовые типы
Целочисленные типы:
byte (8 бит)
sbyte (8 бит)
short (16 бит)
ushort (16 бит)
int (32 бита)
uint (32 бита)
long (64 бита)
ulong (64 бита)
Вещественные типы:
float (32 бита)
double (64 бита)
Десятичный тип:
decimal (128 бит)
Логический тип
bool (1 бит, значения true или false)
Символьный тип
char (16 бит, символы в формате Unicode)

🟠Структуры (Structs)
Пользовательские типы, которые могут содержать поля, свойства и методы. Пример: struct Point { public int X; public int Y; }

🟠Перечисления (Enums)
Специальные типы, представляющие набор именованных констант. Пример: enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }

🟠Nullable Types
Типы, которые могут принимать значение null. Пример: int?, double?

🚩Ссылочные типы (Reference Types)

🟠Классы (Classes)
Основные объекты в C#, могут содержать поля, свойства, методы и события. Пример: class Person { public string Name; public int Age; }

🟠Интерфейсы (Interfaces)
Определяют контракт, который должны реализовать классы. Пример: interface IMovable { void Move(); }

🟠Массивы (Arrays)
Коллекции однотипных элементов. Пример: int[] numbers = new int[5];

🟠Делегаты (Delegates)
Типы, которые представляют собой ссылки на методы. Пример: delegate void Process(int value);

🟠Строки (Strings)
Непосредственно представляют собой последовательность символов. Пример: string message = "Hello, World!";

🟠Записи (Records)
Новый тип в C# 9.0, предназначенный для неизменяемых объектов. Пример: record Person(string Name, int Age);

🚩Примеры и использование

Значимые типы
int a = 5;
float b = 3.14f;
bool isTrue = true;
char letter = 'A';


Ссылочные типы
string message = "Hello, World!";
Person person = new Person { Name = "Alice", Age = 30 };

int[] numbers = new int[] { 1, 2, 3, 4, 5 };


Ставь 👍 и забирай 📚 Базу знаний
🤔 Что такое Dispose?

Это метод интерфейса IDisposable, предназначенный для явного освобождения неуправляемых ресурсов, таких как файловые дескрипторы, сокеты или подключение к базе данных. Его нужно вызывать вручную (или через using), чтобы предотвратить утечки памяти и других ресурсов.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Возможно ли как-нибудь ограничить типы, которые пользователь будет передавать через шаблон?

Можно ограничить типы, которые передаются в шаблоны (generics), с помощью ключевого слова where. Это позволяет указать, какие типы подходят для использования, обеспечивая безопасность и предсказуемость кода. Вот основные виды ограничений:

🟠Класс или структура
where T : class — только классы.
where T : struct — только структуры.

🟠Интерфейс
Указание интерфейса, который должен реализовать тип:

   public class MyClass<T> where T : IDisposable { }


🟠Базовый класс
Указание, что тип должен быть наследником определённого класса:

   public class MyClass<T> where T : Exception { }


🟠Конструктор
Ограничение на наличие конструктора без параметров:

   public class MyClass<T> where T : new() { }


🟠Комбинированные ограничения
Можно объединять несколько условий:

   public class MyClass<T> where T : class, IDisposable, new() { }


Ставь 👍 и забирай 📚 Базу знаний
🤔 Что такое метод Finalize?

Метод Finalize вызывается сборщиком мусора перед удалением объекта из памяти для освобождения неуправляемых ресурсов. Однако его использование не гарантирует немедленного освобождения памяти, поэтому предпочтительнее использовать Dispose.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🔥2
🤔 В чём преимущество блока using?

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

🚩Основные преимущества блока

🟠Автоматическое освобождение ресурсов
Блок using гарантирует, что метод Dispose() будет вызван автоматически, когда выполнение кода выйдет из блока using, даже если возникнет исключение. Это освобождает программиста от необходимости вручную вызывать Dispose() и уменьшает вероятность ошибок.
using (StreamReader reader = new StreamReader("file.txt"))
{
string content = reader.ReadToEnd();
Console.WriteLine(content);
}
// StreamReader автоматически закрывается и освобождает ресурсы после выхода из блока using.


🟠Сокращение количества кода
Использование блока using уменьшает количество необходимого кода для обеспечения правильного освобождения ресурсов.
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// Работа с базой данных
}
// SqlConnection автоматически закрывается и освобождает ресурсы после выхода из блока using.


🟠Повышенная надежность
Блок using повышает надежность кода, так как гарантирует, что ресурсы будут освобождены даже в случае возникновения исключений.
try
{
using (StreamWriter writer = new StreamWriter("file.txt"))
{
writer.WriteLine("Hello, World!");
}
}
catch (Exception ex)
{
Console.WriteLine($"Произошла ошибка: {ex.Message}");
}
// StreamWriter автоматически закрывается и освобождает ресурсы после выхода из блока using, даже если произошла ошибка.


🟠Чистый и понятный код
Код, использующий блок using, выглядит более чистым и упрощает понимание и сопровождение.
using (MemoryStream memoryStream = new MemoryStream())
{
// Работа с MemoryStream
}
// MemoryStream автоматически освобождается после выхода из блока using.


🚩Пример использования блока `using`

Работа с файлами
using System;
using System.IO;

class Program
{
static void Main()
{
using (StreamReader reader = new StreamReader("example.txt"))
{
string content = reader.ReadToEnd();
Console.WriteLine(content);
}
// StreamReader автоматически закрывается и освобождает ресурсы после выхода из блока using.
}
}


Ставь 👍 и забирай 📚 Базу знаний
🤔 Для чего нужно разделение Large Object Heap и Small Object Heap?

Разделение позволяет оптимизировать работу сборщика мусора, так как большие объекты редко перемещаются, а их обработка происходит отдельно, минимизируя накладные расходы.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 В чем разница между FirstOfDefault и SingleOfDefault?

Методы FirstOrDefault и SingleOrDefault в LINQ используются для извлечения элементов из коллекции, но их логика работы отличается. Давайте разберем их подробно, с примерами.

🚩FirstOrDefault

FirstOrDefault возвращает первый элемент коллекции, который удовлетворяет условию (если условие указано), или первый элемент вообще, если условие отсутствует. Если в коллекции нет элементов, метод возвращает значение по умолчанию для типа (например, null для ссылочных типов или 0 для чисел).
Когда вас интересует первый элемент коллекции, но коллекция может быть пустой.
Когда вам неважно, есть ли другие элементы, соответствующие условию.
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

// Возьмем первый элемент, который больше 3
int result = numbers.FirstOrDefault(n => n > 3); // result = 4

// Если условие не выполняется
int result2 = numbers.FirstOrDefault(n => n > 10); // result2 = 0 (default для int)

// Если коллекция пустая
List<int> emptyList = new List<int>();
int result3 = emptyList.FirstOrDefault(); // result3 = 0


🚩SingleOrDefault
SingleOrDefault возвращает единственный элемент из коллекции, который удовлетворяет условию. Если такого элемента нет, метод возвращает значение по умолчанию. Однако если в коллекции есть более одного элемента, удовлетворяющего условию, будет выброшено исключение (InvalidOperationException).
Когда вы ожидаете, что в коллекции будет ровно один элемент, соответствующий условию.
Когда наличие нескольких подходящих элементов является ошибкой и вы хотите это обработать.
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

// Возьмем единственный элемент, равный 3
int result = numbers.SingleOrDefault(n => n == 3); // result = 3

// Если элемента, соответствующего условию, нет
int result2 = numbers.SingleOrDefault(n => n > 10); // result2 = 0

// Если элементов больше одного, возникает исключение
List<int> duplicateNumbers = new List<int> { 1, 2, 3, 3, 4 };
try
{
int result3 = duplicateNumbers.SingleOrDefault(n => n > 2);
}
catch (InvalidOperationException ex)
{
Console.WriteLine(ex.Message); // Ошибка: последовательность содержит несколько элементов
}


Ставь 👍 и забирай 📚 Базу знаний
💊1
🤔 Какие есть типы LINQ?

LINQ делится на несколько типов по источнику данных:
- LINQ to Objects — для коллекций в памяти.
- LINQ to XML — для работы с XML-структурами.
- LINQ to Entities — для доступа к базам данных через Entity Framework.
- LINQ to SQL — устаревший способ работы с SQL.
- LINQ to DataSet — для
ADO.NET DataSet.
- Также возможны кастомные реализации (IQueryable, провайдеры LINQ).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🔥2💊1
🤔 В каком случае использовать интерфейс, в каком абстрактный класс?

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

🚩Когда использовать интерфейсы


🟠Множественное наследование
Класс может реализовывать несколько интерфейсов, но наследоваться только от одного класса. Используйте интерфейсы, когда требуется множественное наследование.
public interface IDriveable
{
void Drive();
}

public interface IFlyable
{
void Fly();
}

public class FlyingCar : IDriveable, IFlyable
{
public void Drive() { /* Реализация вождения */ }
public void Fly() { /* Реализация полета */ }
}


🟠Общее поведение без реализации
Используйте интерфейсы, чтобы определить общий набор методов и свойств без предоставления какой-либо реализации. Это позволяет разным классам реализовать интерфейс по-своему.
public interface IShape
{
double GetArea();
}

public class Circle : IShape
{
public double Radius { get; set; }
public double GetArea() => Math.PI * Radius * Radius;
}

public class Rectangle : IShape
{
public double Width { get; set; }
public double Height { get; set; }
public double GetArea() => Width * Height;
}


🟠Гибкость и полиморфизм
Интерфейсы позволяют легко менять реализацию и обеспечивают гибкость в коде. Можно использовать интерфейсы для создания полиморфных коллекций или методов, которые работают с разными реализациями интерфейсов.
public void DrawShapes(IEnumerable<IShape> shapes)
{
foreach (var shape in shapes)
{
Console.WriteLine($"Area: {shape.GetArea()}");
}
}


🚩Когда использовать

🟠Частичная реализация
Используйте абстрактные классы, если вы хотите предоставить некоторую общую реализацию, которую могут использовать подклассы. Абстрактные классы могут содержать как абстрактные, так и не абстрактные методы.
public abstract class Animal
{
public abstract void MakeSound();
public void Sleep() => Console.WriteLine("Sleeping");
}

public class Dog : Animal
{
public override void MakeSound() => Console.WriteLine("Bark");
}


🟠Шаблонный метод
Абстрактные классы хорошо подходят для реализации паттерна "Шаблонный метод", где общий алгоритм реализован в абстрактном классе, а конкретные шаги определены в подклассах.
public abstract class Game
{
public void Play()
{
Initialize();
StartPlay();
EndPlay();
}

protected abstract void Initialize();
protected abstract void StartPlay();
protected abstract void EndPlay();
}

public class Football : Game
{
protected override void Initialize() => Console.WriteLine("Football Game Initialized");
protected override void StartPlay() => Console.WriteLine("Football Game Started");
protected override void EndPlay() => Console.WriteLine("Football Game Ended");
}


Ставь 👍 и забирай 📚 Базу знаний
🤔 Есть ли разница в какой последовательности писать catch-и?

Да, порядок catch имеет значение!
Исключения проверяются сверху вниз, и первый подходящий catch будет выполнен.

🚩Как работает `catch`?

1. Исключение проверяется по порядку catch-блоков.
2. Если catch подходит → он выполняется, остальные игнорируются.
3. Специфичные исключения (DivideByZeroException) нужно ставить выше общих (Exception).

🚩Ошибка: общий `catch` выше специфичных

Так делать нельзя!
try
{
int x = 5 / 0; // Ошибка
}
catch (Exception ex) // Ловит все исключения
{
Console.WriteLine("Общая ошибка");
}
catch (DivideByZeroException ex) // Никогда не выполнится!
{
Console.WriteLine("Деление на ноль!");
}


Правильный порядок catch
try
{
int x = 5 / 0;
}
catch (DivideByZeroException ex) // Специфичный `catch` первым
{
Console.WriteLine("Ошибка: деление на ноль!");
}
catch (Exception ex) // Общий `catch` внизу
{
Console.WriteLine("Произошла ошибка!");
}


Ставь 👍 и забирай 📚 Базу знаний
🤔 Какие объекты живут в нулевом поколении?

В C# и .NET память управляется сборщиком мусора (Garbage Collector, GC), который делит объекты на три поколения

🟠Generation 0 (Gen 0, нулевое поколение)
самые "молодые" объекты.
🟠Generation 1 (Gen 1, первое поколение)
промежуточные объекты.
🟠Generation 2 (Gen 2, второе поколение)
"долгоживущие" объекты.

🚩Какие объекты попадают в Generation 0?

В Gen 0 живут "короткоживущие" объекты которые создаются и быстро уничтожаются.
Это новые объекты, которые только что были выделены в управляемой куче (Heap).
Обычно это локальные переменные внутри методов, если они не выходят за их пределы.

Пример объектов в Gen 0
class Program
{
static void Main()
{
for (int i = 0; i < 5; i++)
{
var obj = new object(); // Этот объект создаётся в Gen 0
}

GC.Collect(); // Принудительный запуск GC для проверки
}
}


🚩Когда объекты остаются в Gen 0, а когда переходят в следующее поколение?

Если объект быстро умирает → удаляется из Gen 0 при первой же очистке.
Если объект выжил после первой очистки GC → переходит в Gen 1.
Если объект живёт долго → может попасть в Gen 2.

Ставь 👍 и забирай 📚 Базу знаний
🤔 Что такое lock-еры?

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

🚩Как это работает?

Принимает в качестве параметра объект, который используется в качестве мьютекса (взаимоисключающего объекта). Во время выполнения блока кода внутри lock, текущий поток "захватывает" мьютекс. Если другой поток попытается войти в заблокированный участок кода, используя тот же мьютекс, он будет приостановлен до тех пор, пока первый поток не завершит выполнение блока lock и не освободит мьютекс.
public class Account
{
private decimal balance;
private readonly object balanceLock = new object();

public void Deposit(decimal amount)
{
lock (balanceLock)
{
balance += amount;
}
}

public void Withdraw(decimal amount)
{
lock (balanceLock)
{
if (balance >= amount)
{
balance -= amount;
}
}
}
}


🚩Зачем это нужно?

Без использования lock или других методов синхронизации, программы с многопоточным доступом к общим данным могут испытывать проблемы, такие как гонки и условия гонки (race conditions), когда порядок или время доступа к данным может привести к ошибкам или неожиданным результатам. lock гарантирует, что только один поток может исполнять определенный блок кода, работающий с критическими ресурсами, в любой момент времени.

Ставь 👍 и забирай 📚 Базу знаний
👍1