C# | Вопросы собесов
5.1K subscribers
34 photos
1 file
980 links
Download Telegram
🤔 В каких ситуациях проще использовать string, чем StringBuilder?

string удобнее:
- Когда работа со строкой разовая или простая.
- В шаблонах, интерполяции, конкатенации 2–3 элементов.
- При чтении и выводе, где строка уже готова.
То есть в ситуациях, где не требуется частая модификация строки.


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

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
🤔 Как сейчас делается Singleton?

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

🟠Ленивый Singleton (Lazy Initialization)
Ленивый Singleton инициализируется при первом обращении. Это обеспечивает отложенную инициализацию объекта и гарантирует потокобезопасность.
public class Singleton
{
private static readonly Lazy<Singleton> lazyInstance = new Lazy<Singleton>(() => new Singleton());

public static Singleton Instance => lazyInstance.Value;

private Singleton()
{
// Приватный конструктор
}
}


🟠Потокобезопасный Singleton (Thread-safe)
Этот подход использует 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()
{
// Приватный конструктор
}
}


🟠Static Constructor (Статический конструктор)
Использование статического конструктора для инициализации 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
🤔 Что такое паттерн MVVM?

Model-View-ViewModel:
- Model — бизнес-логика.
- ViewModel — логика представления, промежуточный слой.
- View — UI, связанный через биндинг с ViewModel.
Позволяет отделить представление от логики и легко тестировать.


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

В ASP.NET Core жизненный цикл запроса проходит несколько этапов — от получения HTTP-запроса до отправки ответа. В этом процессе участвуют Middleware, контроллеры, фильтры и обработчики событий.

🚩Основные этапы жизненного цикла запроса

Получение запроса (HttpContext создаётся)
Обработка через Middleware (передача запроса вниз)
Маршрутизация (Routing) — определение контроллера
Фильтры (например, аутентификация)
Вызов контроллера и метода (Action)
Обратный проход через Middleware (формирование ответа)
Отправка ответа клиенту

🚩Методы Middleware (Промежуточное ПО)

Middleware — это основной механизм обработки запросов.
Где регистрируются? → В Program.csapp.Use...)
Методы Middleware
app.Use(async (context, next) =>
{
Console.WriteLine("Перед обработкой запроса");
await next(); // Передаём запрос дальше
Console.WriteLine("После обработки запроса");
});


🚩Методы в контроллерах (`Controller`)

Контроллер обрабатывает запросы после маршрутизации.
Основные методы
public class HomeController : Controller
{
// Метод вызывается при GET-запросе
public IActionResult Index()
{
return View();
}

// Метод вызывается при POST-запросе
[HttpPost]
public IActionResult SubmitForm(FormModel model)
{
return RedirectToAction("Index");
}
}


🚩Фильтры (`Filters`)
Фильтры выполняются до и после вызова контроллера.
Методы фильтров
public class MyActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("Перед вызовом метода контроллера");
}

public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("После вызова метода контроллера");
}
}


🚩Методы жизненного цикла в `Program.cs`

В 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?

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?

HashSet<T> — это коллекция уникальных элементов, которая обеспечивает быстрый поиск, добавление и удаление. В основе HashSet<T> лежит хеш-таблица, что делает операции очень быстрыми (почти за O(1) в среднем случае).

🚩Создание и использование `HashSet<T>`

Простой пример
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 и Remove
if (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
🤔 Зачем нужны интерфейсы, если есть абстрактные классы?

Интерфейсы в C# позволяют определять набор методов, которые должны быть реализованы в классах, но не содержат реализации. В отличие от абстрактных классов, интерфейсы не могут содержать полей или реализаций методов (до C# 8.0), и класс может реализовать несколько интерфейсов, но наследовать только один абстрактный класс. Интерфейсы используются для создания гибких архитектур, когда классы могут реализовать множество интерфейсов, предоставляя различные поведения. Они помогают достигать полиморфизма и создавать легко тестируемые системы.

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

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

🟠ConcurrentDictionary<TKey, TValue>
Это словарь, который позволяет безопасно добавлять, удалять и изменять элементы из нескольких потоков одновременно. Он реализует интерфейс 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
}


🟠ConcurrentQueue<T>
Это очередь, которая обеспечивает безопасное добавление элементов в конец и извлечение из начала в многопоточной среде. Она реализует интерфейс 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
}


🟠ConcurrentStack<T>
Это стек, который обеспечивает безопасное добавление и извлечение элементов в многопоточной среде. Он также реализует интерфейс 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
}


🟠ConcurrentBag<T>
Это коллекция, которая позволяет безопасно добавлять и извлекать элементы в многопоточной среде. Она не гарантирует порядок элементов, поэтому используется в случаях, когда порядок не имеет значения.
var concurrentBag = new ConcurrentBag<int>();
concurrentBag.Add(1);
concurrentBag.Add(2);

int result;
if (concurrentBag.TryTake(out result))
{
Console.WriteLine(result); // Output: 1 или 2
}


🟠BlockingCollection<T>
Это коллекция, которая поддерживает ограниченную емкость и блокировку потоков при добавлении или извлечении элементов. Она особенно полезна для реализации паттернов продюсер-потребитель.
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
👍2
🤔 Что в себе может хранить делегат?

Делегат (delegate) — это указатель на метод(ы). Он может хранить:
1. Ссылку на один метод (одиночный делегат)
2. Ссылки на несколько методов (групповой делегат / multicast)
3. Анонимные методы и лямбда-выражения

🚩Делегат хранит ссылку на метод

Делегаты позволяют вызвать метод, даже если его имя заранее неизвестно.
Пример с одиночным делегатом
public delegate void MyDelegate(string message); // Объявляем делегат

public class Program
{
public static void ShowMessage(string msg) => Console.WriteLine($"Сообщение: {msg}");

public static void Main()
{
MyDelegate del = ShowMessage; // Делегат хранит ссылку на метод
del("Привет, делегаты!"); // Вызывает ShowMessage
}
}


🚩Делегат может хранить несколько методов (Multicast)

Делегаты можно связывать с несколькими методами с помощью +=. Пример группового делегата
public delegate void MyDelegate(string message);

public class Program
{
public static void Method1(string msg) => Console.WriteLine($"Метод 1: {msg}");
public static void Method2(string msg) => Console.WriteLine($"Метод 2: {msg}");

public static void Main()
{
MyDelegate del = Method1;
del += Method2; // Добавляем второй метод

del("Привет!");
// Выведет:
// Метод 1: Привет!
// Метод 2: Привет!
}
}


🚩Делегат может хранить анонимные методы и лямбды

Делегаты могут хранить "встроенные" методы (без отдельного определения).
Пример с анонимным методом
MyDelegate del = delegate (string msg) 
{
Console.WriteLine($"Анонимный метод: {msg}");
};
del("Привет!");


Пример с лямбда-выражением
MyDelegate del = msg => Console.WriteLine($"Лямбда: {msg}");
del("Привет!");


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

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


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

Инверсия зависимостей — это принцип SOLID, который говорит:
> Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.

Это значит, что вместо жёстких зависимостей на конкретные классы, код должен работать через абстракции (interface или abstract class).

🚩Проблема без инверсии зависимостей
Допустим, у нас есть класс EmailSender, который отправляет письма:
public class EmailSender
{
public void Send(string message)
{
Console.WriteLine($"Отправка email: {message}");
}
}

public class NotificationService
{
private EmailSender _emailSender = new EmailSender();

public void Notify(string message)
{
_emailSender.Send(message);
}
}


🚩Решение: Инверсия зависимостей

Чтобы избавиться от жёсткой зависимости, вводим абстракцию (IMessageSender):
public interface IMessageSender
{
void Send(string message);
}

public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine($"Отправка email: {message}");
}
}

public class SmsSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine($"Отправка SMS: {message}");
}
}


Теперь NotificationService зависит не от конкретного класса, а от интерфейса:
public class NotificationService
{
private readonly IMessageSender _messageSender;

public NotificationService(IMessageSender messageSender)
{
_messageSender = messageSender;
}

public void Notify(string message)
{
_messageSender.Send(message);
}
}


Теперь мы можем подставлять любую реализацию IMessageSender:
var emailNotifier = new NotificationService(new EmailSender());
emailNotifier.Notify("Привет через Email!");

var smsNotifier = new NotificationService(new SmsSender());
smsNotifier.Notify("Привет через SMS!");


Вывод
Отправка email: Привет через Email!
Отправка SMS: Привет через SMS!


🚩Преимущества инверсии зависимостей

Гибкость – можно легко заменять зависимости.
Тестируемость – можно подставить Mock-объект вместо EmailSender.
Меньше изменений в коде – можно добавить новые способы отправки сообщений без изменения NotificationService.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Forwarded from Идущий к IT
🔥 Записал видос "Как за 3 минуты настроить Автоотклики на вакансии HeadHunter" больше не придется заниматься этой унылой рутиной

📺 Видео: https://youtu.be/G_FOwEGPwlw
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что делать, если есть два интерфейса с одинаковым названием?

В этом случае нужно использовать полное имя интерфейсов с указанием пространства имён (namespace).
Это позволяет разграничить их и избежать конфликта.
Если нужно реализовать оба в одном классе, возможна явная реализация, чтобы уточнить, к какому интерфейсу относится метод.


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

В .NET среде управления памятью, объекты размещаются в куче (heap), и управление памятью осуществляется сборщиком мусора (Garbage Collector, GC). Куча разделена на несколько поколений для оптимизации производительности управления памятью.

🚩Поколения кучи

Куча в .NET разделена на три поколения: Generation 0, Generation 1 и Generation 2. Это разделение позволяет эффективно управлять памятью, минимизируя частоту сборок мусора и оптимизируя их выполнение.

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

🟠Generation 1
Промежуточное поколение, используемое для объектов, которые пережили хотя бы одну сборку мусора Generation 0. Содержит объекты с более длительным временем жизни, чем объекты в Generation 0.

🟠Generation 2
Содержит объекты с самым длительным временем жизни. Наибольший размер среди всех поколений. Сборка мусора для этого поколения происходит реже всего.

🚩Large Object Heap (LOH)

LOH используется для размещения крупных объектов (размером 85,000 байт и более). Объекты в LOH не перемещаются при сборке мусора, что уменьшает фрагментацию памяти. Сборка мусора для LOH происходит одновременно со сборкой Generation 2.

🚩Как разделяются объекты

🟠Размещение объектов
При создании объекта он сначала размещается в Generation 0. Если объект переживает сборку мусора в Generation 0, он перемещается в Generation 1. Если объект переживает сборку мусора в Generation 1, он перемещается в Generation 2.

🟠Сборка мусора
Generation 0: Быстрая и частая сборка. Цель - освободить память от краткоживущих объектов.
Generation 1: Реже, чем Generation 0. Служит промежуточной зоной.
Generation 2: Самая редкая и длительная сборка. Обрабатывает долгоживущие объекты.
Large Object Heap (LOH): Сборка мусора проводится вместе с Generation 2.

public class Program
{
public static void Main()
{
// Создание объектов в Generation 0
for (int i = 0; i < 1000; i++)
{
var obj = new object();
}

// Создание большого объекта (размещается в LOH)
byte[] largeArray = new byte[100000];

// Принудительный вызов сборщика мусора
GC.Collect();

// Проверка поколения объекта
Console.WriteLine(GC.GetGeneration(largeArray)); // Скорее всего, 2
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Внешние ключи должны быть в базе данных?

Внешние ключи обеспечивают целостность данных, связывая таблицы.
1. Они полезны для предотвращения ошибок, например, удаления связанных записей.
2. Однако в некоторых случаях (например, масштабируемые системы) можно использовать программную логику вместо внешних ключей для повышения производительности.


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