ref позволяет передавать переменные по ссылке, сохраняя изменения, а out требует инициализации переменной в методе.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
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>();
Определение интерфейсов и реализаций
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
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Описывает, насколько элементы внутри модуля связаны между собой. Высокая связанность (хорошая) означает, что элементы модуля работают над одной задачей.
public class FileProcessor
{
public void ProcessFile(string filePath)
{
ReadFile(filePath);
ParseData();
SaveResults();
}
private void ReadFile(string filePath) { /* чтение файла */ }
private void ParseData() { /* парсинг данных */ }
private void SaveResults() { /* сохранение результатов */ }
}
Описывает зависимость между модулями. Низкая связность (хорошая) означает, что модули минимально зависят друг от друга.
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
👍7❤2🤔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
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥2❤1
Это паттерн проектирования, который используется для внедрения зависимостей объектов. Он помогает улучшить модульность, тестируемость и гибкость кода. Рассмотрим, зачем нужен 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>();
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);
}
}
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
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это интерфейс в .NET, который предоставляет механизм для высвобождения неуправляемых ресурсов. Он содержит один метод
Dispose, который должен быть реализован классами, использующими неуправляемые ресурсы, такие как файловые дескрипторы, соединения с базами данных или ресурсы ОС.Это освобождение ресурсов, которые не управляются средой CLR (Common Language Runtime). Такие ресурсы не могут быть автоматически освобождены сборщиком мусора, поэтому необходимо явно управлять их жизненным циклом.
Метод
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
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это два механизма синхронизации, используемые для управления доступом к общим ресурсам в многопоточном программировании. Хотя они часто используются для схожих целей, между ними есть важные различия.
Только один поток может владеть мьютексом в данный момент времени.
Поток, который захватил мьютекс, становится его владельцем и может его освободить.
Мьютексы обычно реализуются на уровне ядра операционной системы, что делает их более тяжелыми в плане ресурсов.
Обычно используется для синхронизации доступа к критическим секциям кода.
public class Example
{
private static Mutex mutex = new Mutex();
public void UseResource()
{
mutex.WaitOne(); // Захват мьютекса
try
{
// Критическая секция
}
finally
{
mutex.ReleaseMutex(); // Освобождение мьютекса
}
}
}
Семафор имеет счетчик, который отслеживает количество разрешений. Потоки уменьшают счетчик при входе и увеличивают при выходе.
В отличие от мьютекса, семафор позволяет нескольким потокам одновременно получать доступ к ресурсу, если счетчик больше нуля.
Используется для управления доступом к ограниченным ресурсам, таким как пул соединений, доступ к базе данных и т. д.
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
В веб-приложениях, например, в ASP.NET Core, обрабатывает HTTP-запросы и формирует HTTP-ответы. Каждое 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 может завершить обработку запроса и сразу вернуть ответ. Например, проверка аутентификации может вернуть 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 вызывает следующий компонент в конвейере, то окончательный ответ может быть сформирован этим компонентом или одним из последующих.
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
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤1🔥1
Это паттерн проектирования поведенческих шаблонов, который позволяет уменьшить связанность между объектами, обеспечивая взаимодействие через центральный объект-посредник. Медиатор упрощает коммуникацию между компонентами системы, делая ее более модульной и легкой для сопровождения.
public interface IMediator
{
void Notify(object sender, string ev);
}
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);
}
}
}
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");
}
}
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
👍3❤1