string удобнее:
- Когда работа со строкой разовая или простая.
- В шаблонах, интерполяции, конкатенации 2–3 элементов.
- При чтении и выводе, где строка уже готова.
То есть в ситуациях, где не требуется частая модификация строки.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1🤔1
lock используется для управления доступом к ресурсам в многопоточных приложениях. Это предотвращает возникновение проблем, связанных с одновременным доступом нескольких потоков к одному и тому же ресурсу, что может привести к непредсказуемому поведению или коррупции данных.
Принимает в качестве параметра объект, который используется в качестве мьютекса (взаимоисключающего объекта). Во время выполнения блока кода внутри
lock, текущий поток "захватывает" мьютекс. Если другой поток попытается войти в заблокированный участок кода, используя тот же мьютекс, он будет приостановлен до тех пор, пока первый поток не завершит выполнение блока lock и не освободит мьютекс.public class Account
{
private decimal balance;
private readonly object balanceLock = new object();
public void Deposit(decimal amount)
{
lock (balanceLock)
{
balance += amount;
}
}
public void Withdraw(decimal amount)
{
lock (balanceLock)
{
if (balance >= amount)
{
balance -= amount;
}
}
}
}
Без использования
lock или других методов синхронизации, программы с многопоточным доступом к общим данным могут испытывать проблемы, такие как гонки и условия гонки (race conditions), когда порядок или время доступа к данным может привести к ошибкам или неожиданным результатам. lock гарантирует, что только один поток может исполнять определенный блок кода, работающий с критическими ресурсами, в любой момент времени.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1. One-way binding — от источника к UI. Применяется при отображении.
2. Two-way binding — синхронизация UI и модели. Применяется в формах.
3. One-time binding — однократная установка значения при инициализации.
4. Event binding — привязка событий.
Используется в WPF, Xamarin, Blazor и других MVVM-фреймворках.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
В современном C# паттерн Singleton можно реализовать несколькими способами, каждый из которых имеет свои преимущества и предназначен для различных сценариев использования. Рассмотрим несколько распространенных подходов к реализации Singleton.
Ленивый Singleton инициализируется при первом обращении. Это обеспечивает отложенную инициализацию объекта и гарантирует потокобезопасность.
public class Singleton
{
private static readonly Lazy<Singleton> lazyInstance = new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance => lazyInstance.Value;
private Singleton()
{
// Приватный конструктор
}
}
Этот подход использует
lock для обеспечения потокобезопасности при создании экземпляра.public class Singleton
{
private static Singleton instance;
private static readonly object lockObj = new object();
private Singleton()
{
// Приватный конструктор
}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (lockObj)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
Eager Initialization (Инициализация при загрузке)
Экземпляр Singleton создается при загрузке класса. Это гарантирует потокобезопасность за счет особенностей инициализации статических переменных в .NET.
public class Singleton
{
private static readonly Singleton instance = new Singleton();
public static Singleton Instance => instance;
private Singleton()
{
// Приватный конструктор
}
}
Использование статического конструктора для инициализации Singleton.
public class Singleton
{
private static readonly Singleton instance;
static Singleton()
{
instance = new Singleton();
}
public static Singleton Instance => instance;
private Singleton()
{
// Приватный конструктор
}
}
Singleton с внедрением зависимостей (Dependency Injection)
В современных приложениях, особенно с использованием ASP.NET Core, Singleton часто регистрируется в контейнере внедрения зависимостей.
public class SingletonService
{
public void DoWork()
{
// Выполнение работы
}
}
// Регистрация в контейнере служб
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<SingletonService>();
}
// Использование в контроллере
public class MyController : ControllerBase
{
private readonly SingletonService _singletonService;
public MyController(SingletonService singletonService)
{
_singletonService = singletonService;
}
public IActionResult Index()
{
_singletonService.DoWork();
return Ok();
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Model-View-ViewModel:
- Model — бизнес-логика.
- ViewModel — логика представления, промежуточный слой.
- View — UI, связанный через биндинг с ViewModel.
Позволяет отделить представление от логики и легко тестировать.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В ASP.NET Core жизненный цикл запроса проходит несколько этапов — от получения HTTP-запроса до отправки ответа. В этом процессе участвуют Middleware, контроллеры, фильтры и обработчики событий.
Получение запроса (
HttpContext создаётся) Обработка через Middleware (передача запроса вниз)
Маршрутизация (Routing) — определение контроллера
Фильтры (например, аутентификация)
Вызов контроллера и метода (
Action) Обратный проход через Middleware (формирование ответа)
Отправка ответа клиенту
Middleware — это основной механизм обработки запросов.
Где регистрируются? → В
Program.cs (в app.Use...) Методы Middleware
app.Use(async (context, next) =>
{
Console.WriteLine("Перед обработкой запроса");
await next(); // Передаём запрос дальше
Console.WriteLine("После обработки запроса");
});
Контроллер обрабатывает запросы после маршрутизации.
Основные методы
public class HomeController : Controller
{
// Метод вызывается при GET-запросе
public IActionResult Index()
{
return View();
}
// Метод вызывается при POST-запросе
[HttpPost]
public IActionResult SubmitForm(FormModel model)
{
return RedirectToAction("Index");
}
}
Фильтры выполняются до и после вызова контроллера.
Методы фильтров
public class MyActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("Перед вызовом метода контроллера");
}
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("После вызова метода контроллера");
}
}
В ASP.NET Core 6+ вся конфигурация находится в
Program.cs. Методы инициализации
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews(); // Подключаем MVC
var app = builder.Build();
app.UseRouting(); // Включаем маршрутизацию
app.UseAuthorization(); // Проверка прав
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers(); // Подключаем контроллеры
});
app.Run();
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊1
Swagger (теперь часть OpenAPI):
- Это инструмент для документирования REST API.
- Позволяет:
- описывать API в формате JSON/YAML;
- автоматически генерировать документацию;
- предоставлять интерактивный UI, где можно тестировать запросы.
- Интеграция с .NET происходит через Swashbuckle.AspNetCore или NSwag.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍2
HashSet<T> — это коллекция уникальных элементов, которая обеспечивает быстрый поиск, добавление и удаление. В основе HashSet<T> лежит хеш-таблица, что делает операции очень быстрыми (почти за O(1) в среднем случае).Простой пример
HashSet<int> numbers = new HashSet<int> { 1, 2, 3, 4, 5 };
// Добавление элементов (дубликаты не добавляются)
numbers.Add(3); // Уже есть в HashSet, не добавится
numbers.Add(6); // Добавится
// Вывод всех элементов
foreach (int num in numbers)
{
Console.Write(num + " ");
}Вывод
1 2 3 4 5 6
Пример работы с
Contains и Removeif (numbers.Contains(3))
{
numbers.Remove(3);
}
Console.WriteLine(string.Join(", ", numbers));
Вывод
1, 2, 4, 5, 6
HashSet<T> поддерживает математические операции над множествами, такие как пересечение, объединение и разность.Пересечение (
IntersectWith)HashSet<int> set1 = new HashSet<int> { 1, 2, 3, 4 };
HashSet<int> set2 = new HashSet<int> { 3, 4, 5, 6 };
set1.IntersectWith(set2); // Оставит только {3, 4}
Console.WriteLine(string.Join(", ", set1));Вывод
3, 4
Объединение (
UnionWith)set1 = new HashSet<int> { 1, 2, 3 };
set2 = new HashSet<int> { 3, 4, 5 };
set1.UnionWith(set2); // set1 = {1, 2, 3, 4, 5}
Console.WriteLine(string.Join(", ", set1));Вывод
1, 2, 3, 4, 5
Разность (
ExceptWith)set1 = new HashSet<int> { 1, 2, 3, 4, 5 };
set2 = new HashSet<int> { 3, 4 };
set1.ExceptWith(set2); // Удалит {3, 4}, останется {1, 2, 5}
Console.WriteLine(string.Join(", ", set1));Вывод
1, 2, 5
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Конкурентные коллекции — это специализированные коллекции, которые обеспечивают безопасное выполнение операций в многопоточной среде. В стандартной библиотеке .NET существуют несколько типов таких коллекций, каждая из которых предназначена для различных сценариев использования. Давайте рассмотрим основные из них.
Это словарь, который позволяет безопасно добавлять, удалять и изменять элементы из нескольких потоков одновременно. Он реализует интерфейс
IDictionary<TKey, TValue>.var concurrentDictionary = new ConcurrentDictionary<int, string>();
concurrentDictionary.TryAdd(1, "value1");
concurrentDictionary.TryAdd(2, "value2");
string value;
if (concurrentDictionary.TryGetValue(1, out value))
{
Console.WriteLine(value); // Output: value1
}
Это очередь, которая обеспечивает безопасное добавление элементов в конец и извлечение из начала в многопоточной среде. Она реализует интерфейс
IProducerConsumerCollection<T>.var concurrentQueue = new ConcurrentQueue<int>();
concurrentQueue.Enqueue(1);
concurrentQueue.Enqueue(2);
int result;
if (concurrentQueue.TryDequeue(out result))
{
Console.WriteLine(result); // Output: 1
}
Это стек, который обеспечивает безопасное добавление и извлечение элементов в многопоточной среде. Он также реализует интерфейс
IProducerConsumerCollection<T>.var concurrentStack = new ConcurrentStack<int>();
concurrentStack.Push(1);
concurrentStack.Push(2);
int result;
if (concurrentStack.TryPop(out result))
{
Console.WriteLine(result); // Output: 2
}
Это коллекция, которая позволяет безопасно добавлять и извлекать элементы в многопоточной среде. Она не гарантирует порядок элементов, поэтому используется в случаях, когда порядок не имеет значения.
var concurrentBag = new ConcurrentBag<int>();
concurrentBag.Add(1);
concurrentBag.Add(2);
int result;
if (concurrentBag.TryTake(out result))
{
Console.WriteLine(result); // Output: 1 или 2
}
Это коллекция, которая поддерживает ограниченную емкость и блокировку потоков при добавлении или извлечении элементов. Она особенно полезна для реализации паттернов продюсер-потребитель.
var blockingCollection = new BlockingCollection<int>(boundedCapacity: 5);
Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
blockingCollection.Add(i);
Console.WriteLine($"Added {i}");
}
blockingCollection.CompleteAdding();
});
foreach (var item in blockingCollection.GetConsumingEnumerable())
{
Console.WriteLine($"Consumed {item}");
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Да, можно. В C# для ограничения (ограничений) обобщённых типов используется ключевое слово where.
Примеры ограничений:
- where T : class — только ссылочные типы.
- where T : struct — только значимые типы.
- where T : new() — должен иметь публичный конструктор без параметров.
- where T : BaseClass — должен быть наследником BaseClass.
- where T : interfaceName — должен реализовывать указанный интерфейс.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM