es
Feedback
C# | Вопросы собесов

C# | Вопросы собесов

Ir al canal en Telegram
5 063
Suscriptores
-324 horas
-57 días
-1230 días
Archivo de publicaciones
🤔 Что такое unsafe? Используется для объявления небезопасного контекста кода, который позволяет выполнять низкоуровневые операции, такие как манипуляции с указателями. Эти операции обычно не разрешены в безопасном управляемом коде, но могут быть необходимы для взаимодействия с неуправляемым кодом, оптимизации производительности или доступа к определенным системным ресурсам. 🚩Характеристики 🟠Объявление небезопасного контекста Чтобы использовать указатели и выполнять небезопасные операции, нужно объявить метод, блок кода или тип как unsafe.
unsafe void UnsafeMethod()
{
    int a = 10;
    int* p = &a; // Использование указателя
    Console.WriteLine(*p); // Разыменование указателя
}
🟠Компиляция с поддержкой `unsafe` Для компиляции кода с unsafe необходимо включить поддержку небезопасного кода в настройках проекта. В Visual Studio это делается через свойства проекта: 1⃣Откройте свойства проекта. 2⃣Перейдите на вкладку "Сборка". 3⃣Установите флажок "Разрешить небезопасный код". 🟠Использование указателей Указатели позволяют напрямую работать с адресами памяти, что может быть полезно для некоторых оптимизаций или взаимодействия с низкоуровневым кодом, написанным на C или C++.
unsafe void PointerExample()
{
    int a = 5;
    int* p = &a; // p указывает на адрес переменной a
    Console.WriteLine((int)p); // Вывод адреса переменной a
    Console.WriteLine(*p); // Вывод значения переменной a через указатель
}
🟠Небезопасные структуры Вы можете объявлять структуры с указателями и использовать их в небезопасном контексте.
unsafe struct UnsafeStruct
{
    public int* Pointer;
}
🟠Стековые указатели (stackalloc) stackalloc позволяет выделять память в стеке для массива в небезопасном контексте. Это может быть быстрее, чем выделение памяти в куче.
unsafe void StackAllocExample()
{
    int* array = stackalloc int[10]; // Выделение массива из 10 целых чисел в стеке
    for (int i = 0; i < 10; i++)
    {
        array[i] = i;
    }
}
🟠Взаимодействие с неуправляемым кодом Небезопасный код часто используется для взаимодействия с API, написанными на других языках, такими как C или C++.
[DllImport("user32.dll")]
extern static unsafe int MessageBox(IntPtr hWnd, char* text, char* caption, int options);

unsafe void CallUnmanagedCode()
{
    char* text = "Hello, World!";
    char* caption = "My Message Box";
    MessageBox(IntPtr.Zero, text, caption, 0);
}
🚩Плюсы Производительность Позволяет выполнять высокоэффективные операции с памятью. ➕Взаимодействие с неуправляемым кодом Необходим для вызова функций из библиотек, написанных на других языках. ➕Низкоуровневый контроль Предоставляет возможность прямого управления памятью и аппаратными ресурсами. Ставь 👍 и забирай 📚 Базу знаний

🤔 Какие есть структуры данных? - Линейные: массивы, списки, стеки, очереди. - Связные: односвязные, двусвязные списки. - Хеш-таблицы: Dictionary, HashMap. - Деревья: бинарные, AVL, красно-чёрные. - Графы: ориентированные, неориентированные. - Кучи, матрицы, множества, деки, очереди с приоритетом. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое аутентификация? Когда человек вводит логин и пароль, система аутентифицирует его, проверяя, действительно ли это тот, за кого он себя выдаёт. 🚩Как работает аутентификация? Пользователь вводит данные (например, логин и пароль). Система проверяет их в базе данных. Если данные верны → доступ разрешён. Если данные неверны → отказ в доступе.
public async Task<IActionResult> Login(string username, string password)
{
    var user = await _userManager.FindByNameAsync(username);
    if (user != null && await _userManager.CheckPasswordAsync(user, password))
    {
        await _signInManager.SignInAsync(user, isPersistent: false);
        return RedirectToAction("Index", "Home");
    }
    ModelState.AddModelError("", "Неверный логин или пароль");
    return View();
}
🚩Виды аутентификации 🟠По паролю Самый распространённый вариант. Минус: если пароль украден – доступ открыт. 🟠Двухфакторная (2FA) Например, SMS-код + пароль. Усложняет взлом аккаунта. 🟠Биометрическая Отпечаток пальца, Face ID. Удобно, но требует спецоборудования. 🟠OAuth (Google, Facebook, GitHub) Вход через соцсети. Удобно, не нужно запоминать пароль. 🟠Аутентификация по токену (JWT) Используется в API и микросервисах. Позволяет работать без сохранения сессий. Ставь 👍 и забирай 📚 Базу знаний

🤔 Могут ли объекты структур лежать в куче? Да, могут. Хотя структуры (value-types) обычно хранятся в стеке, они переносятся в кучу, когда: - используются как поля классов; - захватываются замыканием; - приводятся к интерфейсу или object (boxing). Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое медиатор? Это паттерн проектирования поведенческих шаблонов, который позволяет уменьшить связанность между объектами, обеспечивая взаимодействие через центральный объект-посредник. Медиатор упрощает коммуникацию между компонентами системы, делая ее более модульной и легкой для сопровождения. 🚩Примеры использования 1⃣Определение интерфейса медиатора
public interface IMediator
{
    void Notify(object sender, string ev);
}   
2⃣Реализация медиатора
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);
        }
    }
}   
3⃣Компоненты, взаимодействующие через медиатора
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");
    }
}  
4⃣Использование медиатора в приложении
var button = new Button();
var textBox = new TextBox();
var mediator = new DialogMediator(button, textBox);

textBox.EnterText(); // Ввод текста активирует кнопку
button.Click();      // Нажатие кнопки очищает текстовое поле   
🚩Плюсы и минусыСнижение связанности Компоненты не взаимодействуют напрямую, а используют медиатор. ➕Упрощение поддержки Вся логика взаимодействия сосредоточена в одном месте. ➕Повышение модульности Легко добавлять новые компоненты или изменять существующие. ➖Усложнение медиатора Медиатор может стать сложным, если в него добавляется много логики. ➖Единая точка отказа Если медиатор выходит из строя, это может повлиять на всю систему. Ставь 👍 и забирай 📚 Базу знаний

🤔 Для чего используются readonly поля? readonly поля: - могут быть присвоены только при инициализации или в конструкторе; - защищают от изменений после создания объекта; - полезны для неизменяемых зависимостей или константной конфигурации. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Приведи пример паттерна строитель в С# Паттерн "Строитель" (Builder) используется для пошагового создания сложных объектов. Он удобен, когда объект имеет много параметров и возможных конфигураций. 🚩Проблема без паттерна "Строитель" Допустим, у нас есть класс Car, и мы хотим создавать машины с разными конфигурациями:
public class Car
{
    public string Engine { get; set; }
    public int Wheels { get; set; }
    public bool HasSunroof { get; set; }

    public override string ToString()
    {
        return $"Car: Engine={Engine}, Wheels={Wheels}, Sunroof={HasSunroof}";
    }
}
Создавать объект через конструкторы или инициализаторы становится неудобно, если у нас много параметров:
var car1 = new Car { Engine = "V8", Wheels = 4, HasSunroof = true };
var car2 = new Car { Engine = "V6", Wheels = 4, HasSunroof = false };
🚩Решение с использованием паттерна "Строитель" Сделаем пошаговый процесс сборки объекта с помощью паттерна "Строитель". Шаг 1: Создаём интерфейс строителя
public interface ICarBuilder
{
    ICarBuilder SetEngine(string engine);
    ICarBuilder SetWheels(int wheels);
    ICarBuilder SetSunroof(bool hasSunroof);
    Car Build();
}
Шаг 2: Реализуем конкретного строителя
public class CarBuilder : ICarBuilder
{
    private Car _car = new Car(); // Временный объект

    public ICarBuilder SetEngine(string engine)
    {
        _car.Engine = engine;
        return this; // Возвращаем самого себя для цепочки вызовов
    }

    public ICarBuilder SetWheels(int wheels)
    {
        _car.Wheels = wheels;
        return this;
    }

    public ICarBuilder SetSunroof(bool hasSunroof)
    {
        _car.HasSunroof = hasSunroof;
        return this;
    }

    public Car Build()
    {
        return _car; // Возвращаем готовый объект
    }
}
Шаг 3: Используем строителя
class Program
{
    static void Main()
    {
        ICarBuilder builder = new CarBuilder();

        Car sportsCar = builder
            .SetEngine("V8")
            .SetWheels(4)
            .SetSunroof(true)
            .Build();

        Car economyCar = builder
            .SetEngine("V4")
            .SetWheels(4)
            .SetSunroof(false)
            .Build();

        Console.WriteLine(sportsCar);
        Console.WriteLine(economyCar);
    }
}
Вывод в консоли
Car: Engine=V8, Wheels=4, Sunroof=True
Car: Engine=V4, Wheels=4, Sunroof=False
Ставь 👍 и забирай 📚 Базу знаний

🤔 Когда можно использовать using? using используется для управления объектами, реализующими интерфейс IDisposable, чтобы гарантировать освобождение ресурсов. Это удобно для работы с файлами, потоками, базами данных и другими ресурсами, требующими явного закрытия. Код внутри блока using автоматически вызывает метод Dispose для объекта, даже если возникло исключение. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое делегаты и зачем они нужны? Делегаты — это типы, которые безопасно инкапсулируют методы, подобно указателям на функции в других языках программирования, но с проверкой типов во время компиляции. Могут ссылаться на метод, который принимает параметры и возвращает значение. Они используются для реализации обратных вызовов и событий, а также для определения пользовательских операций, которые могут быть выполнены методом, принимаемым в качестве параметра. 🚩Зачем они нужны? 🟠Обратные вызовы (Callbacks) Делегаты предоставляют механизм для передачи методов в качестве аргументов другим методам. Это полезно для реализации обратных вызовов, позволяя вызывать методы в ответ на определенные события или условия. 🟠События Являются основой системы событий. Они позволяют определять события и подписываться на них. Когда событие происходит, вызываются делегаты, связанные с этим событием, что позволяет реагировать на изменения или действия пользователя. 🟠Параметризация методами Позволяют создавать более гибкие и масштабируемые приложения, поскольку методы могут быть переданы и использованы динамически в различных контекстах. 🟠Асинхронное программирование Используются для асинхронного программирования, позволяя выполнять задачи в фоновом режиме, не блокируя основной поток приложения.
public delegate int Operation(int x, int y);

public class Calculator
{
    public int PerformOperation(int x, int y, Operation op)
    {
        return op(x, y);
    }
}

class Program
{
    static int Add(int x, int y)
    {
        return x + y;
    }

    static int Multiply(int x, int y)
    {
        return x * y;
    }

    static void Main()
    {
        Calculator calc = new Calculator();

        // Создание делегата для метода Add и вызов через метод PerformOperation
        Operation addOp = new Operation(Add);
        int result = calc.PerformOperation(5, 6, addOp);
        Console.WriteLine("Addition: " + result);

        // Создание делегата для метода Multiply и вызов через метод PerformOperation
        Operation mulOp = new Operation(Multiply);
        result = calc.PerformOperation(5, 6, mulOp);
        Console.WriteLine("Multiplication: " + result);
    }
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое интерфейс? Интерфейс — это контракт, который определяет набор методов и свойств, которые класс обязан реализовать. В отличие от классов, интерфейсы не содержат реализации, что позволяет разрабатывать гибкие и расширяемые архитектуры, где конкретное поведение зависит от реализации. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Какая есть классификация у кучи? В информатике и программировании куча (heap) может классифицироваться по нескольким критериям. Рассмотрим основные виды: 🟠По назначению: Куча памяти (Memory Heap) Используется для динамического выделения памяти в приложениях. В C# это управляется сборщиком мусора (GC - Garbage Collector). Примеры: объекты, созданные с помощью new, выделяются в управляемой куче. 🟠Структура данных «Куча» (Heap Data Structure) Это специальная бинарная структура данных, используемая в алгоритмах, например, в сортировке (Heap Sort) или в приоритетных очередях. Бывает максимальная куча (max-heap) и минимальная куча (min-heap). 🚩По типу управления памятью (для кучи памяти в языках программирования): 🟠Управляемая куча (Managed Heap) В C# и .NET память выделяется и освобождается автоматически с помощью GC. Разделяется на поколения (Generation 0, 1, 2), что оптимизирует работу сборщика мусора. 🟠Неуправляемая куча (Unmanaged Heap) Применяется в C/C++ и низкоуровневом коде, где управление памятью выполняется вручную (malloc/free, new/delete). В C# тоже можно работать с ней через Marshal или Unsafe код. 🟠По структуре данных (Heap Data Structure): 🟠Максимальная куча (Max Heap) Корневой узел содержит наибольшее значение, а дочерние узлы – меньшее. Используется в алгоритмах приоритетных очередей. 🟠Минимальная куча (Min Heap) Корневой узел содержит наименьшее значение, а дочерние узлы – большее. Применяется в алгоритме Дейкстры и других задачах.
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        PriorityQueue<int, int> minHeap = new PriorityQueue<int, int>();

        minHeap.Enqueue(5, 5);
        minHeap.Enqueue(3, 3);
        minHeap.Enqueue(8, 8);
        minHeap.Enqueue(1, 1);

        while (minHeap.Count > 0)
        {
            Console.WriteLine(minHeap.Dequeue()); // Выведет: 1, 3, 5, 8
        }
    }
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое CancellationToken в многопоточности? CancellationToken — это объект, который позволяет управлять отменой операций, особенно асинхронных. Используется для: - Прерывания задач Task, async-await - Передачи сигнала отмены в долгоживущие процессы (загрузки, ожидания) - Контроля над временем жизни операции С помощью CancellationTokenSource можно отправить команду отмены, и все обработчики, использующие связанный токен, корректно завершат выполнение. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое исключения? Исключения в программировании — это механизмы обработки ошибок и необычных ситуаций, которые возникают во время выполнения программы. В C# и других языках программирования исключения позволяют отделить код обработки ошибок от основного кода программы, что упрощает его чтение и поддержку. 🚩Основные понятия 🟠Исключение (Exception) Событие, которое прерывает нормальный поток выполнения программы. 🟠Блок try Содержит код, который может вызвать исключение. 🟠Блок catch Содержит код, который выполняется, если возникает исключение. В catch блок можно передать параметр — экземпляр исключения, которое произошло. 🟠Блок finally Содержит код, который выполняется в любом случае, независимо от того, произошло исключение или нет. Обычно используется для освобождения ресурсов. 🟠Бросание исключения (throw) Механизм для явного вызова исключения. 🚩Пример использования Основные блоки
try
{
    // Код, который может вызвать исключение
    int divisor = 0;
    int result = 10 / divisor;
}
catch (DivideByZeroException ex)
{
    // Обработка исключения
    Console.WriteLine("Деление на ноль невозможно.");
}
finally
{
    // Код, который выполнится в любом случае
    Console.WriteLine("Блок finally выполнен.");
}
Создание и бросание собственного исключения
public class InvalidAgeException : Exception
{
    public InvalidAgeException(string message) : base(message) { }
}

public void SetAge(int age)
{
    if (age < 0)
    {
        throw new InvalidAgeException("Возраст не может быть отрицательным.");
    }
    // Логика установки возраста
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Какие известны правила наименования в REST? REST-принципы ориентированы на читаемость и предсказуемость URL. Вот основные правила: - Использовать существительные во множественном числе для ресурсов: /users, /orders, /products. - Использовать HTTP-глаголы для операций, а не глаголы в URI: /getUsers, GET /users. - Иерархическая структура: /users/123/orders — заказы конкретного пользователя. - Без заглавных букв: использовать kebab-case или snake_case: /user-profile, /user_profile. - Не включать действия в путь, они определяются методом: DELETE /users/123 — удаление, а не /deleteUser. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое примитив синхронзиации semaphore? Это механизм синхронизации, который используется для управления доступом к ограниченному ресурсу. Он позволяет ограниченному количеству потоков одновременно использовать общий ресурс. 🚩Как работает семафор? Семафор использует счётчик для отслеживания доступных "разрешений": Когда поток запрашивает доступ к ресурсу, семафор уменьшает счётчик. Если счётчик больше нуля, поток получает доступ. Если счётчик равен нулю, поток блокируется, пока другой поток не освободит ресурс (увеличив счётчик). 🚩Пример использования `SemaphoreSlim` В .NET часто используется SemaphoreSlim, так как он более лёгкий и эффективный, чем Semaphore.
using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static SemaphoreSlim semaphore = new SemaphoreSlim(2); // Разрешаем максимум 2 потока одновременно

    static async Task AccessResource(int id)
    {
        Console.WriteLine($"Поток {id} ждёт доступа...");
        await semaphore.WaitAsync(); // Захватываем семафор
        try
        {
            Console.WriteLine($"Поток {id} получил доступ!");
            await Task.Delay(2000); // Имитация работы с ресурсом
        }
        finally
        {
            Console.WriteLine($"Поток {id} освобождает ресурс.");
            semaphore.Release(); // Освобождаем семафор
        }
    }

    static async Task Main()
    {
        Task[] tasks = new Task[5];
        for (int i = 0; i < 5; i++)
        {
            tasks[i] = AccessResource(i);
        }
        await Task.WhenAll(tasks);
    }
}
🚩Обычный `Semaphore` Если нужна синхронизация между разными процессами, можно использовать Semaphore
Semaphore semaphore = new Semaphore(2, 2, "MyGlobalSemaphore");
Ставь 👍 и забирай 📚 Базу знаний

🤔 Является ли POST идемпотентным? Нет, метод POST не является идемпотентным. Каждый повторный вызов POST может создавать новые ресурсы или изменять состояние системы, что приводит к разным результатам. Это типичный метод для операций создания или изменения, и его повторение может вызвать дублирование или непредсказуемый эффект. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Пример выполнения кода, когда возвращается объект интерфейса Iqueryable? IQueryable<T> — это интерфейс, который используется для отложенного выполнения запросов (deferred execution). Он позволяет строить SQL-запросы к базе данных или манипулировать данными в памяти, но сам запрос выполняется только в момент его итерации (ToList(), FirstOrDefault(), Count(), и т. д.). 🚩Пример работы с `IQueryable<T>` на Entity Framework Core Предположим, у нас есть сущность Product и контекст базы данных AppDbContext
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class AppDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("YourConnectionString");
    }
}
Теперь создадим репозиторий, который возвращает IQueryable<Product>
public class ProductRepository
{
    private readonly AppDbContext _context;

    public ProductRepository(AppDbContext context)
    {
        _context = context;
    }

    public IQueryable<Product> GetProducts()
    {
        return _context.Products.Where(p => p.Price > 100); 
        // Запрос не выполняется здесь! Только формируется
    }
}
🚩Вызов метода и выполнение запроса Запрос к базе данных выполнится только при материализации (ToList(), FirstOrDefault(), Count(), и т. д.).
var repository = new ProductRepository(new AppDbContext());

// Создаём IQueryable-запрос
IQueryable<Product> query = repository.GetProducts();

// Добавляем дополнительное условие (запрос еще НЕ выполнен)
query = query.OrderBy(p => p.Name);

// Теперь выполняем запрос к БД
List<Product> products = query.ToList(); // SQL-запрос отправляется в базу
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое предикат? Это делегат, представляющий метод, который принимает параметр и возвращает булево значение (true или false). Используется для фильтрации данных в LINQ или коллекциях. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Какой сейчас последний C#? 🚩Нововведения 🟠Primary Constructors для классов и структур Позволяют определять конструкторы прямо в объявлении класса или структуры, что упрощает код и улучшает его читаемость.
public class Person(string name, int age)
{
    public string Name { get; } = name;
    public int Age { get; } = age;
}
🟠Collection Literals Обеспечивает более удобный синтаксис для создания коллекций.
var numbers = [1, 2, 3, 4, 5];
🟠Default Values для auto-properties Теперь можно задавать значения по умолчанию для auto-properties, что делает код более лаконичным.
public string Name { get; set; } = "Unknown";
🟠Using aliases Позволяет использовать алиасы для пространств имен, улучшая читаемость кода.
using Text = System.Text;
🟠Improved Lambda Expressions: Улучшены возможности для работы с лямбда-выражениями, делая их более гибкими и мощными. 🚩Зачем нужны эти изменения? Эти нововведения направлены на упрощение синтаксиса языка, улучшение читаемости и поддерживаемости кода, а также на повышение производительности и удобства разработки.
public class Program
{
    public static void Main()
    {
        var person = new Person("John", 30);
        Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");

        var numbers = [1, 2, 3, 4, 5];
        numbers.ForEach(n => Console.WriteLine(n));

        var name = new Name { Value = "Unknown" };
        Console.WriteLine(name.Value);
    }
}

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

public class Name
{
    public string Value { get; set; } = "Default Name";
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Можно ли в рамках lock использовать await? Нет, нельзя. Ожидание с await может привести к тому, что поток выйдет из текущего блока и продолжит выполнение в другом — это нарушает правила lock, который должен оставаться в одном потоке. Для асинхронного кода используют другие механизмы синхронизации. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний