C# | Вопросы собесов
5.1K subscribers
35 photos
1 file
982 links
Download Telegram
🤔 Что из себя представляет абстракция?

Это один из ключевых принципов объектно-ориентированного программирования (ООП), который позволяет выделять важные характеристики объекта, игнорируя несущественные детали. Абстракция упрощает сложные системы, предоставляя только те аспекты, которые необходимы для выполнения конкретной задачи.

🚩Аспекты

🟠Скрытие деталей реализации
Абстракция позволяет скрыть сложные детали реализации и предоставлять простой интерфейс для взаимодействия с объектом.
public abstract class Animal
{
public abstract void MakeSound();
}

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


🟠Определение интерфейсов и абстрактных классов
Интерфейсы и абстрактные классы являются основными инструментами абстракции в C#. Интерфейсы определяют контракт, который должен быть реализован классами, а абстрактные классы могут содержать как реализацию, так и абстрактные методы.
public interface IShape
{
double GetArea();
}

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

public abstract class Vehicle
{
public abstract void Move();
}

public class Car : Vehicle
{
public override void Move()
{
Console.WriteLine("Car is moving");
}
}


🚩Сокрытие ненужных деталей

Абстракция помогает пользователям взаимодействовать с объектом через его публичный интерфейс, не беспокоясь о внутренних деталях.
public class CoffeeMachine
{
public void MakeCoffee()
{
HeatWater();
BrewCoffee();
PourCoffee();
}

private void HeatWater() { /* Подогрев воды */ }
private void BrewCoffee() { /* Заваривание кофе */ }
private void PourCoffee() { /* Наливание кофе */ }
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое интерфейс?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Если не будем использовать абстракции, что может произойти?

🟠Сложность и запутанность кода
Без абстракций код станет более сложным и трудным для понимания, так как все детали реализации будут видны пользователю. Это затруднит работу с кодом, особенно в больших проектах.

🟠Повышенная связанность
Классы и модули будут сильно зависеть друг от друга, что приведет к высокой связанности. Это затруднит изменения и рефакторинг кода, так как любое изменение в одном месте потребует изменений в других местах.

🟠Низкая повторная использование
Без абстракций код будет менее модульным и его будет трудно повторно использовать в других проектах или частях проекта.

🟠Сложность тестирования
Код без абстракций труднее тестировать, так как сложно изолировать отдельные части системы для юнит-тестирования. Это может привести к большему количеству ошибок и дефектов в коде.

🟠Затрудненное сопровождение
Код станет труднее поддерживать и сопровождать, так как его будет сложно изменять, исправлять ошибки или добавлять новые функции без риска сломать существующую функциональность.

🚩Примеры проблем

Без абстракции
public class UserService
{
public void RegisterUser(string username, string password)
{
// Логика регистрации пользователя
var db = new Database();
db.SaveUser(username, password);
}
}

public class Database
{
public void SaveUser(string username, string password)
{
// Сохранение пользователя в базу данных
}
}


С использованием абстракции
public interface IUserRepository
{
void SaveUser(string username, string password);
}

public class UserService
{
private readonly IUserRepository _userRepository;

public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}

public void RegisterUser(string username, string password)
{
// Логика регистрации пользователя
_userRepository.SaveUser(username, password);
}
}

public class Database : IUserRepository
{
public void SaveUser(string username, string password)
{
// Сохранение пользователя в базу данных
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Что такое SignalR?

SignalR — это библиотека от Microsoft для обеспечения двусторонней связи в реальном времени между клиентом и сервером. Она использует протоколы, такие как WebSockets, для высокой производительности, а в случае их недоступности — другие технологии, например, long polling. SignalR упрощает разработку чатов, уведомлений и других динамичных приложений.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥21
🤔 Для чего нужен Dependency injection?

Это паттерн проектирования, который используется для внедрения зависимостей объектов. Он помогает улучшить модульность, тестируемость и гибкость кода. Рассмотрим, зачем нужен Dependency Injection и какие преимущества он приносит.

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

🟠Снижение связанности кода
DI позволяет классам не зависеть от конкретных реализаций своих зависимостей. Вместо этого зависимости передаются извне, обычно через конструкторы, методы или свойства. Это уменьшает связанность и делает код более модульным.
public class UserService
{
private readonly IUserRepository _userRepository;

public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}

public void RegisterUser(string username, string password)
{
_userRepository.SaveUser(username, password);
}
}


🟠Улучшение тестируемости
DI упрощает создание юнит-тестов, так как зависимости могут быть заменены на моки или стабы. Это позволяет изолировать тестируемый код и тестировать его без зависимости от реальных объектов.
[Test]
public void RegisterUser_ShouldCallSaveUser()
{
var mockRepository = new Mock<IUserRepository>();
var userService = new UserService(mockRepository.Object);

userService.RegisterUser("testuser", "password");

mockRepository.Verify(r => r.SaveUser("testuser", "password"), Times.Once);
}


🟠Повышение гибкости и расширяемости
DI позволяет легко заменять реализации зависимостей, что упрощает изменение поведения приложения без необходимости модифицировать код, использующий эти зависимости.
var services = new ServiceCollection();
services.AddTransient<IUserRepository, SqlUserRepository>(); // или MemoryUserRepository
services.AddTransient<UserService>();

var serviceProvider = services.BuildServiceProvider();
var userService = serviceProvider.GetService<UserService>();


🟠Управление жизненным циклом объектов
DI-контейнеры управляют созданием, временем жизни и удалением объектов, что позволяет лучше контролировать ресурсы и повышает эффективность использования памяти.
services.AddSingleton<IConfiguration>(new Configuration());
services.AddScoped<IDatabaseContext, DatabaseContext>();
services.AddTransient<IUserRepository, UserRepository>();


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

1⃣Определение интерфейсов и реализаций
public interface IMessageService
{
void SendMessage(string message);
}

public class EmailService : IMessageService
{
public void SendMessage(string message)
{
Console.WriteLine($"Email sent: {message}");
}
}

public class SmsService : IMessageService
{
public void SendMessage(string message)
{
Console.WriteLine($"SMS sent: {message}");
}
}


2⃣Внедрение зависимостей через конструктор
public class NotificationController
{
private readonly IMessageService _messageService;

public NotificationController(IMessageService messageService)
{
_messageService = messageService;
}

public void Notify(string message)
{
_messageService.SendMessage(message);
}
}


3⃣Настройка DI-контейнера
var services = new ServiceCollection();
services.AddTransient<IMessageService, EmailService>(); // или SmsService
services.AddTransient<NotificationController>();

var serviceProvider = services.BuildServiceProvider();
var controller = serviceProvider.GetService<NotificationController>();

controller.Notify("Hello World!");


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍2🔥1
🤔 Какие механизмы позволяют не нарушать принцип dependency inversion?

Для соблюдения принципа dependency inversion используются интерфейсы и абстракции, которые позволяют код зависеть от общего поведения, а не от конкретных реализаций. Также помогают фабрики (Factories) для создания объектов и DI-контейнеры (Dependency Injection), которые управляют зависимостями и их внедрением.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое Idisposable?

Это интерфейс в .NET, который предоставляет механизм для высвобождения неуправляемых ресурсов. Он содержит один метод Dispose, который должен быть реализован классами, использующими неуправляемые ресурсы, такие как файловые дескрипторы, соединения с базами данных или ресурсы ОС.

🚩Основная цель

Это освобождение ресурсов, которые не управляются средой CLR (Common Language Runtime). Такие ресурсы не могут быть автоматически освобождены сборщиком мусора, поэтому необходимо явно управлять их жизненным циклом.

🚩Метод `Dispose`

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

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

Реализация IDisposable для класса с неуправляемыми ресурсами
public class ResourceHolder : IDisposable
{
private bool _disposed = false; // Для отслеживания вызова Dispose

// Метод для освобождения ресурсов
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // Подавляет финализацию
}

// Защищенный метод для освобождения ресурсов
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// Освобождаем управляемые ресурсы
}

// Освобождаем неуправляемые ресурсы
_disposed = true;
}
}

~ResourceHolder()
{
Dispose(false);
}
}


Использование using для автоматического вызова Dispose
public void UseResource()
{
using (var resourceHolder = new ResourceHolder())
{
// Работа с ресурсом
} // Здесь автоматически вызовется Dispose
}


Ставь
👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🤔 Что такое Action Executor и Action Executing?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 В чем разница между семафором и mutex?

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

🚩Мьютекс

🟠Взаимоисключение
Только один поток может владеть мьютексом в данный момент времени.
🟠Владелец
Поток, который захватил мьютекс, становится его владельцем и может его освободить.
🟠Блокировка на уровне ядра
Мьютексы обычно реализуются на уровне ядра операционной системы, что делает их более тяжелыми в плане ресурсов.
🟠Использование
Обычно используется для синхронизации доступа к критическим секциям кода.

public class Example
{
private static Mutex mutex = new Mutex();

public void UseResource()
{
mutex.WaitOne(); // Захват мьютекса
try
{
// Критическая секция
}
finally
{
mutex.ReleaseMutex(); // Освобождение мьютекса
}
}
}


🚩Семафор (Semaphore)

🟠Счетчик
Семафор имеет счетчик, который отслеживает количество разрешений. Потоки уменьшают счетчик при входе и увеличивают при выходе.

🟠Многократный доступ
В отличие от мьютекса, семафор позволяет нескольким потокам одновременно получать доступ к ресурсу, если счетчик больше нуля.

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

public class Example
{
private static Semaphore semaphore = new Semaphore(3, 3); // Максимум 3 потока

public void UseResource()
{
semaphore.WaitOne(); // Захват семафора
try
{
// Критическая секция
}
finally
{
semaphore.Release(); // Освобождение семафора
}
}
}


🚩Ключевые различия:

🟠Владелец
Мьютекс: Может быть освобожден только потоком, который его захватил.
Семафор: Может быть освобожден любым потоком.

🟠Количество потоков
Мьютекс: Разрешает доступ только одному потоку.
Семафор: Разрешает доступ нескольким потокам, количество которых ограничено счетчиком.

🟠Использование
Мьютекс: Используется для защиты критических секций, где необходим доступ только одного потока.
Семафор: Используется для управления доступом к ресурсам, которые могут быть использованы одновременно несколькими потоками, но в ограниченном количестве.

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

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14
🤔 Что такое абстракция?

Абстракция — это принцип ООП, который выделяет только важные характеристики объекта, скрывая сложные детали его реализации. Это помогает упростить взаимодействие с объектами и сконцентрироваться на их использовании, а не на внутренней структуре.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🤯2🔥1
🤔 Как middleware возвращает ответ?

В веб-приложениях, например, в ASP.NET Core, обрабатывает HTTP-запросы и формирует HTTP-ответы. Каждое middleware-компонент выполняет свою работу и передает управление следующему компоненту в конвейере или завершает обработку и формирует ответ.

🚩Основные моменты работы middleware

🟠Обработка запроса
Middleware получает запрос и может его обработать частично или полностью.
🟠Вызов следующего middleware
Если middleware не формирует окончательный ответ, оно вызывает следующий компонент в конвейере.
🟠Формирование ответа
Middleware может завершить обработку запроса, сформировав ответ, или пропустить управление следующему компоненту.

🚩Пример работы

Простое middleware
public class SimpleMiddleware
{
private readonly RequestDelegate _next;

public SimpleMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
// Обработка запроса до следующего middleware
Console.WriteLine("Handling request.");

// Передача управления следующему middleware в конвейере
await _next(context);

// Обработка ответа после следующего middleware
Console.WriteLine("Handling response.");
}
}


Регистрация middleware в конвейере
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMiddleware<SimpleMiddleware>();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello, World!");
});
}


🚩Возвращение ответа

🟠В самом middleware
Middleware может завершить обработку запроса и сразу вернуть ответ. Например, проверка аутентификации может вернуть 401 Unauthorized.
public class AuthMiddleware
{
private readonly RequestDelegate _next;

public AuthMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
if (!context.User.Identity.IsAuthenticated)
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsync("Unauthorized");
return; // Завершаем обработку, не вызывая _next
}

await _next(context);
}
}


🟠Через вызов следующего middleware
Если middleware вызывает следующий компонент в конвейере, то окончательный ответ может быть сформирован этим компонентом или одним из последующих.
public class LoggingMiddleware
{
private readonly RequestDelegate _next;

public LoggingMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
// Логирование до обработки запроса
Console.WriteLine("Request incoming");

await _next(context);

// Логирование после обработки запроса
Console.WriteLine("Response outgoing");
}
}


🚩Ключевые моменты

🟠Последовательность
Middleware компоненты вызываются последовательно, в том порядке, в котором они зарегистрированы в Configure.
🟠Передача управления
Каждый middleware может передать управление следующему компоненту или завершить обработку, вернув ответ.
🟠Обработка ответа
После вызова следующего middleware текущий компонент может выполнять дополнительные действия с ответом (например, логирование).

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Что такое join в SQL?

JOIN — это операция в SQL, которая объединяет строки из двух или более таблиц на основе связующего условия. Существуют разные типы JOIN, такие как INNER JOIN (только совпадающие строки), LEFT JOIN (все строки из левой таблицы) и другие, обеспечивающие гибкость работы с данными.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81🔥1
🤔 Что такое медиатор?

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

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

1⃣Определение интерфейса медиатора
public interface IMediator
{
void Notify(object sender, string ev);
}


2⃣Реализация медиатора
public class DialogMediator : IMediator
{
private Button _button;
private TextBox _textBox;

public DialogMediator(Button button, TextBox textBox)
{
_button = button;
_button.SetMediator(this);
_textBox = textBox;
_textBox.SetMediator(this);
}

public void Notify(object sender, string ev)
{
if (ev == "ButtonClick")
{
_textBox.Clear();
}
else if (ev == "TextBoxEnter")
{
_button.SetEnabled(true);
}
}
}


3⃣Компоненты, взаимодействующие через медиатора
public class Button
{
private IMediator _mediator;

public void SetMediator(IMediator mediator)
{
_mediator = mediator;
}

public void Click()
{
Console.WriteLine("Button clicked");
_mediator.Notify(this, "ButtonClick");
}

public void SetEnabled(bool enabled)
{
Console.WriteLine($"Button is {(enabled ? "enabled" : "disabled")}");
}
}

public class TextBox
{
private IMediator _mediator;

public void SetMediator(IMediator mediator)
{
_mediator = mediator;
}

public void EnterText()
{
Console.WriteLine("Text entered");
_mediator.Notify(this, "TextBoxEnter");
}

public void Clear()
{
Console.WriteLine("TextBox cleared");
}
}


4⃣Использование медиатора в приложении
var button = new Button();
var textBox = new TextBox();
var mediator = new DialogMediator(button, textBox);

textBox.EnterText(); // Ввод текста активирует кнопку
button.Click(); // Нажатие кнопки очищает текстовое поле


🚩Плюсы и минусы

Снижение связанности
Компоненты не взаимодействуют напрямую, а используют медиатор.
Упрощение поддержки
Вся логика взаимодействия сосредоточена в одном месте.
Повышение модульности
Легко добавлять новые компоненты или изменять существующие.
Усложнение медиатора
Медиатор может стать сложным, если в него добавляется много логики.
Единая точка отказа
Если медиатор выходит из строя, это может повлиять на всю систему.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31
🤔 Как работает async/await?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
🤔 Как в EF испольузем join`ы?

В Entity Framework (EF) join операции используются для объединения данных из нескольких таблиц на основе связанных полей. В EF можно использовать как метод синтаксиса, так и синтаксис запросов (LINQ). Рассмотрим оба подхода на примерах.

🚩Метод синтаксиса (Method Syntax)

Метод синтаксиса предоставляет методы расширения для выполнения join операций. Допустим, у нас есть две сущности: Student и Enrollment, где Enrollment содержит StudentId, который является внешним ключом, связывающим эти две сущности.
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
}

public class Enrollment
{
public int EnrollmentId { get; set; }
public int StudentId { get; set; }
public string Course { get; set; }
}


Использование метода синтаксиса
using (var context = new SchoolContext())
{
var query = context.Students
.Join(context.Enrollments,
student => student.StudentId,
enrollment => enrollment.StudentId,
(student, enrollment) => new
{
StudentName = student.Name,
Course = enrollment.Course
})
.ToList();

foreach (var item in query)
{
Console.WriteLine($"Student: {item.StudentName}, Course: {item.Course}");
}
}


🚩Синтаксис запросов (Query Syntax)

Синтаксис запросов использует выражения LINQ, которые похожи на SQL-запросы. Тот же пример с Student и Enrollment, но с использованием синтаксиса запросов.
using (var context = new SchoolContext())
{
var query = (from student in context.Students
join enrollment in context.Enrollments
on student.StudentId equals enrollment.StudentId
select new
{
StudentName = student.Name,
Course = enrollment.Course
}).ToList();

foreach (var item in query)
{
Console.WriteLine($"Student: {item.StudentName}, Course: {item.Course}");
}
}


🚩Типы `join` операций

🟠Inner Join
Соединяет строки из двух таблиц, когда есть совпадения по ключу.
🟠Left Join
Возвращает все строки из левой таблицы и совпадающие строки из правой таблицы. Если совпадений нет, результатом будет null для правой таблицы.

using (var context = new SchoolContext())
{
var query = from student in context.Students
join enrollment in context.Enrollments
on student.StudentId equals enrollment.StudentId
into studentEnrollments
from se in studentEnrollments.DefaultIfEmpty()
select new
{
StudentName = student.Name,
Course = se?.Course ?? "No Course"
};

foreach (var item in query.ToList())
{
Console.WriteLine($"Student: {item.StudentName}, Course: {item.Course}");
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔6👍41
🤔 В чем разница между процессами и потоками?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
🤔 Если в двух переменных хранится одинаковое значение, то будут ли они равны?

Сравнение значений переменных может зависеть от типа данных, хранящихся в этих переменных, и от способа их сравнения.

🟠Примитивные типы (Value Types)
Для примитивных типов (например, int, float, char, bool) значение хранятся непосредственно в переменных, и их сравнение выполняется по значению.
int a = 5;
int b = 5;

bool areEqual = (a == b); // True


🟠Ссылочные типы (Reference Types)
Для ссылочных типов (например, классы, строки) переменные содержат ссылки на объекты в куче. Сравнение ссылочных типов по умолчанию выполняется по ссылке, а не по значению.
class Person
{
public string Name { get; set; }
}

Person person1 = new Person { Name = "Alice" };
Person person2 = new Person { Name = "Alice" };

bool areEqual = (person1 == person2); // False, потому что сравниваются ссылки


🟠Строки (Strings)
Строки являются ссылочными типами, но переопределяют операторы сравнения == и Equals для сравнения по значению.
string str1 = "Hello";
string str2 = "Hello";

bool areEqual = (str1 == str2); // True, строки сравниваются по значению


🟠Кастомные классы
Для кастомных классов можно переопределить методы Equals и GetHashCode, чтобы сравнивать объекты по значению.
class Person
{
public string Name { get; set; }

public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;

Person other = (Person)obj;
return Name == other.Name;
}

public override int GetHashCode()
{
return Name.GetHashCode();
}
}

Person person1 = new Person { Name = "Alice" };
Person person2 = new Person { Name = "Alice" };

bool areEqual = person1.Equals(person2); // True


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍72
🤔 Какие проблемы могут быть при многопоточности и как их избежать?

Проблемы: состояния гонки, deadlock, livelock, взаимные блокировки и неправильная синхронизация данных. Их избегают с помощью использования примитивов синхронизации (например, lock, Monitor, Mutex), разделения ответственности между потоками, атомарных операций и минимизации общего доступа к ресурсам.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 Что надо сделать, чтобы сравнить коллекции по содержимому?

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

🚩Способы сравнения

Использование `SequenceEqual`
Этот метод сравнивает две последовательности (например, списки или массивы) на основе значений элементов. Поддерживает опциональный параметр IEqualityComparer<T> для пользовательского сравнения.

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

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
public static void Main()
{
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 1, 2, 3 };
var list3 = new List<int> { 3, 2, 1 };

bool areEqual = list1.SequenceEqual(list2); // True
bool areEqualDifferentOrder = list1.SequenceEqual(list3); // False

Console.WriteLine(areEqual);
Console.WriteLine(areEqualDifferentOrder);
}
}


🟠Сравнение коллекций с пользовательским компаратором
Для сравнения коллекций сложных объектов можно использовать IEqualityComparer<T>.
using System;
using System.Collections.Generic;
using System.Linq;

public class Person
{
public string Name { get; set; }
public int Age { get; set; }

public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;

Person other = (Person)obj;
return Name == other.Name && Age == other.Age;
}

public override int GetHashCode()
{
return HashCode.Combine(Name, Age);
}
}

public class PersonEqualityComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
if (x == null || y == null)
return false;

return x.Name == y.Name && x.Age == y.Age;
}

public int GetHashCode(Person obj)
{
return obj.GetHashCode();
}
}

public class Program
{
public static void Main()
{
var list1 = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 25 }
};

var list2 = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 25 }
};

bool areEqual = list1.SequenceEqual(list2, new PersonEqualityComparer()); // True

Console.WriteLine(areEqual);
}
}


🟠Сравнение наборов (Sets)
Для сравнения unordered коллекций, таких как HashSet, можно использовать методы SetEquals.
using System;
using System.Collections.Generic;

public class Program
{
public static void Main()
{
var set1 = new HashSet<int> { 1, 2, 3 };
var set2 = new HashSet<int> { 3, 2, 1 };

bool areEqual = set1.SetEquals(set2); // True

Console.WriteLine(areEqual);
}
}


🟠Сравнение словарей (Dictionaries)
Для сравнения словарей можно сравнивать их ключи и значения.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41
🤔 Что такое IEnumerable?

IEnumerable — это интерфейс в .NET для перебора коллекций с помощью цикла foreach. Он предоставляет метод GetEnumerator, возвращающий объект, позволяющий обходить элементы коллекции по одному. Это основа для работы с последовательностями в LINQ и других структурах данных.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥3