C# | Вопросы собесов
5.1K subscribers
35 photos
1 file
981 links
Download Telegram
🤔 Когда использовать классы, а когда структуры?

Выбор между классами и структурами в 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
🤔 Что из себя представляет абстракция?

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

🚩Аспекты

🟠Скрытие деталей реализации
Абстракция позволяет скрыть сложные детали реализации и предоставлять простой интерфейс для взаимодействия с объектом.
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