C# | Вопросы собесов
5.1K subscribers
35 photos
1 file
982 links
Download Telegram
🤔 Есть ref out и boxing unboxing в чем их разница?

ref передаёт переменные по ссылке, out требует их инициализации в методе, boxing/unboxing преобразуют тип значения в объект и обратно.

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

Сравнение содержимого объектов классов в C# можно выполнить несколькими способами. Наиболее распространенные методы включают переопределение методов Equals и GetHashCode, а также реализацию интерфейса IEquatable<T> и использование библиотек для глубокого сравнения.

🟠Переопределение методов Equals и GetHashCode
Для сравнения содержимого классов можно переопределить методы Equals и GetHashCode. Это позволяет определить логику сравнения объектов на основе их полей.
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);
}
}


🟠Реализация интерфейса IEquatable<T>
Позволяет улучшить производительность сравнения и сделать код более читаемым.
public class Person : IEquatable<Person>
{
public string Name { get; set; }
public int Age { get; set; }

public bool Equals(Person other)
{
if (other == null)
return false;

return Name == other.Name && Age == other.Age;
}

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

return Equals((Person)obj);
}

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


🟠Использование библиотек для глубокого сравнения
Существуют библиотеки, такие как DeepEqual или Json.NET, которые позволяют выполнять глубокое сравнение объектов, автоматически сравнивая все их поля и свойства.
using KellermanSoftware.CompareNetObjects;

public class Program
{
public static void Main()
{
Person person1 = new Person { Name = "Alice", Age = 30 };
Person person2 = new Person { Name = "Alice", Age = 30 };

var compareLogic = new CompareLogic();
ComparisonResult result = compareLogic.Compare(person1, person2);

Console.WriteLine(result.AreEqual); // True
}
}


🟠Сравнение через сериализацию
Ещё один способ сравнить содержимое объектов - это сериализовать их в JSON и затем сравнить полученные строки.
using Newtonsoft.Json;

public class Program
{
public static void Main()
{
Person person1 = new Person { Name = "Alice", Age = 30 };
Person person2 = new Person { Name = "Alice", Age = 30 };

string json1 = JsonConvert.SerializeObject(person1);
string json2 = JsonConvert.SerializeObject(person2);

bool areEqual = json1 == json2;
Console.WriteLine(areEqual); // True
}
}


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

Equals проверяет логическое равенство объектов, а == сравнивает ссылки для объектов и значения для примитивов.

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

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

🟠Тип данных
Классы: являются ссылочными типами (reference types). Переменные класса хранят ссылки на объекты, которые размещены в куче (heap).
Структуры: являются значимыми типами (value types). Переменные структуры хранят сами данные, и эти данные размещаются на стеке (stack) или в куче, если структура является частью объекта класса.

🟠Передача данных
Классы: при передаче объекта класса по значению (например, в метод) передается ссылка на объект, а не сам объект.
Структуры: при передаче структуры по значению передается копия всех данных структуры.

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

🟠Наследование
Классы: поддерживают наследование (можно наследоваться от другого класса и реализовывать интерфейсы).
Структуры: не поддерживают наследование от других структур или классов, но могут реализовывать интерфейсы.

🟠Размер и производительность
Классы: из-за размещения в куче и необходимости сборки мусора (garbage collection) могут быть медленнее при частом создании и удалении объектов.
Структуры: часто эффективнее по памяти и времени выполнения для небольших объектов, которые создаются и уничтожаются часто, благодаря размещению на стеке.

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

🚩Пример

Класса
public class Person
{
public string Name { get; set; }
public int Age { get; set; }

public Person(string name, int age)
{
Name = name;
Age = age;
}
}


Структуры
public struct Point
{
public int X { get; set; }
public int Y { get; set; }

public Point(int x, int y)
{
X = x;
Y = y;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🤔 В чём отличие thread от task?

Thread — это поток ОС, а Task — абстракция для работы с асинхронным кодом, которая легче и управляется планировщиком.

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

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

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

🟠Наследование и полиморфизм
Используйте классы, когда требуется наследование (один класс наследуется от другого) или полиморфизм (переменная может принимать значения различных типов, связанных наследованием).
public class Animal
{
public virtual void MakeSound() { }
}

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


🟠Сложные объекты
Если объект имеет сложное состояние или ведет себя как сущность с богатым набором методов и свойств, лучше использовать класс.

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

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

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

🟠Небольшие, неизменяемые объект
Структуры лучше использовать для небольших объектов, которые не содержат большого количества полей. Они должны быть неизменяемыми после создания (immutable).

🟠Значимые типы
Если объект представляет собой значение, которое логически является единым целым (например, координаты точки, комплексное число), структура подходит лучше.

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

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

🚩Примеры

Использование класса
public class Car
{
public string Make { get; set; }
public string Model { get; set; }
public int Year { get; set; }

public void StartEngine()
{
Console.WriteLine("Engine started");
}
}


Использование структуры
public struct Point
{
public int X { get; }
public int Y { get; }

public Point(int x, int y)
{
X = x;
Y = y;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2
🤔 Как работает в JS сборщик мусора?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥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");
}


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

Поколения разделяют объекты по возрасту, ускоряя сборку за счёт частой проверки короткоживущих объектов.

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

Принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP) гласит, что объекты подклассов должны быть заменяемы объектами базового класса без нарушения ожидаемого поведения программы. Нарушение этого принципа часто проявляется в наследовании, где подклассы изменяют поведение, что может привести к неожиданным результатам.

🚩Пример с прямоугольником и квадратом

Предположим, у нас есть базовый класс Rectangle и производный класс Square. Класс Rectangle имеет свойства Width и Height и метод для вычисления площади. Класс Square наследуется от Rectangle и устанавливает одинаковые значения для ширины и высоты.
public class Rectangle
{
public virtual int Width { get; set; }
public virtual int Height { get; set; }

public int GetArea()
{
return Width * Height;
}
}

public class Square : Rectangle
{
public override int Width
{
set
{
base.Width = value;
base.Height = value;
}
}

public override int Height
{
set
{
base.Width = value;
base.Height = value;
}
}
}


🚩Нарушение LSP

Нарушение принципа Лисков проявляется в том, что Square изменяет поведение базового класса Rectangle. Рассмотрим пример использования этих классов:
public void ProcessRectangle(Rectangle rect)
{
rect.Width = 10;
rect.Height = 5;
Console.WriteLine($"Expected Area: {10 * 5}");
Console.WriteLine($"Actual Area: {rect.GetArea()}");
}


Если мы вызовем метод ProcessRectangle с экземпляром класса Rectangle, все будет работать корректно:
Rectangle rect = new Rectangle();
ProcessRectangle(rect); // Expected Area: 50, Actual Area: 50


Однако, если мы передадим экземпляр класса Square, поведение изменится:
Square square = new Square();
ProcessRectangle(square); // Expected Area: 50, Actual Area: 25


🚩Причина нарушения

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

🚩Решение:

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

Использование композиции
public abstract class Shape
{
public abstract int GetArea();
}

public class Rectangle : Shape
{
public int Width { get; set; }
public int Height { get; set; }

public override int GetArea()
{
return Width * Height;
}
}

public class Square : Shape
{
public int Side { get; set; }

public override int GetArea()
{
return Side * Side;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какие API можно назвать REST-овыми?

REST API используют HTTP-методы, ресурсы представляются как URL, и архитектура основана на простоте и масштабируемости.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3😁3👍2
🤔 Использование интерфейса уже является dependency inversion?

Использование интерфейсов в программировании может способствовать соблюдению принципа инверсии зависимостей (Dependency Inversion Principle, DIP), но само по себе использование интерфейсов не гарантирует полное соблюдение этого принципа. Давайте разберем подробнее, что такое принцип инверсии зависимостей и как интерфейсы помогают его соблюдать.

🚩Принцип инверсии зависимостей (DIP)

Принцип инверсии зависимостей является одним из пяти принципов SOLID, которые определяют лучшие практики объектно-ориентированного проектирования и программирования. DIP гласит:
Высокоуровневые модули не должны зависеть от низкоуровневых модулей. Оба должны зависеть от абстракций.
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Это означает, что модули на более высоком уровне логики не должны зависеть от реализации конкретных классов на более низком уровне. Вместо этого они должны зависеть от абстракций, таких как интерфейсы или абстрактные классы.

🚩Как интерфейсы помогают соблюдать DIP

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

Без соблюдения DIP
public class EmailService
{
public void SendEmail(string to, string message)
{
// Логика отправки email
}
}

public class NotificationService
{
private EmailService _emailService;

public NotificationService()
{
_emailService = new EmailService();
}

public void Notify(string to, string message)
{
_emailService.SendEmail(to, message);
}
}


С соблюдением DIP
public interface INotificationService
{
void Notify(string to, string message);
}

public class EmailService : INotificationService
{
public void Notify(string to, string message)
{
// Логика отправки email
}
}

public class SmsService : INotificationService
{
public void Notify(string to, string message)
{
// Логика отправки SMS
}
}

public class NotificationService
{
private readonly INotificationService _notificationService;

public NotificationService(INotificationService notificationService)
{
_notificationService = notificationService;
}

public void NotifyUser(string to, string message)
{
_notificationService.Notify(to, message);
}
}


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

ref позволяет передавать переменные по ссылке, сохраняя изменения, а out требует инициализации переменной в методе.


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

Dependency Injection (DI) используется для управления зависимостями объектов в приложении. Это шаблон проектирования, который помогает реализовать принцип инверсии зависимостей (DIP) из SOLID-принципов. DI делает код более модульным, тестируемым и гибким. Рассмотрим ключевые цели и преимущества использования Dependency Injection.

🚩Основные цели

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

// Зависимость внедряется через конструктор
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}

public void CreateUser(string name)
{
_userRepository.AddUser(name);
}
}


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

userService.CreateUser("John Doe");

mockRepository.Verify(r => r.AddUser("John Doe"), Times.Once);
}


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


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

Определение интерфейсов и реализаций
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}");
}
}


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

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

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


Настройка 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
👍1
🤔 Как работает Entity Framework?

EF преобразует данные из базы в объекты .NET, поддерживает LINQ-запросы и управление миграциями.

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

🚩Связанность (Cohesion)

Описывает, насколько элементы внутри модуля связаны между собой. Высокая связанность (хорошая) означает, что элементы модуля работают над одной задачей.
public class FileProcessor
{
public void ProcessFile(string filePath)
{
ReadFile(filePath);
ParseData();
SaveResults();
}

private void ReadFile(string filePath) { /* чтение файла */ }
private void ParseData() { /* парсинг данных */ }
private void SaveResults() { /* сохранение результатов */ }
}


🚩Связность (Coupling)

Описывает зависимость между модулями. Низкая связность (хорошая) означает, что модули минимально зависят друг от друга.
public interface IDataService
{
void SaveData(string data);
}

public class DataService : IDataService
{
public void SaveData(string data) { /* сохранение данных */ }
}

public class Processor
{
private readonly IDataService _dataService;

public Processor(IDataService dataService)
{
_dataService = dataService;
}

public void Process(string data)
{
_dataService.SaveData(data);
}
}


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

Инкапсуляция скрывает детали реализации объекта, предоставляя доступ через публичные методы для защиты данных.

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

Это ситуация, когда один объект сильно зависит от другого, что затрудняет их независимое изменение и тестирование. Например, если изменение в одном объекте требует изменений в другом объекте, то связь между ними считается тесной.
public class DataService
{
public void SaveData(string data) { /* Сохранение данных */ }
}

public class Processor
{
private DataService _dataService = new DataService();

public void Process(string data)
{
_dataService.SaveData(data);
}
}


Уменьшенная связность
public interface IDataService
{
void SaveData(string data);
}

public class DataService : IDataService
{
public void SaveData(string data) { /* Сохранение данных */ }
}

public class Processor
{
private readonly IDataService _dataService;

public Processor(IDataService dataService)
{
_dataService = dataService;
}

public void Process(string data)
{
_dataService.SaveData(data);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Как сделать миграцию методов?

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

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