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

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

前往频道在 Telegram
5 050
订阅者
无数据24 小时
-77
-1530
帖子存档
Разработчики, девопсы, сисадмины: 📲 внимание, внимание! Похоже, эпоха открытого исходного кода идёт к концу: одна за одной н
Разработчики, девопсы, сисадмины: 📲 внимание, внимание! Похоже, эпоха открытого исходного кода идёт к концу: одна за одной наши любимые бесплатные C#-библиотеки становятся платными. И что же теперь делать? Давайте соберёмся вместе и подумаем. Приглашаем вас на открытую онлайн-дискуссию «Библиотеки C# уходят в платную сферу: конец эры опенсорса?» 📌Узнаете, какие библиотеки уже стали платными и что ждёт экосистему дальше 📌Узнаете, чем конкретно можно заменить ту или иную библиотеку 📌Сможете уменьшить лицензионные риски 📌Сможете вовремя изменить карьерный вектор или поменять архитектуру проектов 📌 Получите экспертные рекомендации по архитектуре и устойчивым решениям Спикеры: 👨‍💻Олег Голенищев – старший разработчик в Directum 👨‍💻Антон Герасименко – ведущий .NET-разработчик. Всем участникам – скидка 7% на любой курс OTUS и подборка альтернативных библиотек с открытым исходным кодом в подарок. 27 мая, 19:00 МСК Бесплатно по записи: https://tglink.io/1d79e8379db9 Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963. erid: 2W5zFH7KtCg

🤔 Что такое asp.net? ASP.NET — это фреймворк для веб-разработки, предоставляемый Microsoft, который позволяет разработчикам строить динамичные веб-сайты, веб-приложения и веб-сервисы. Он основан на .NET Framework и поддерживает языки программирования, такие как C#, VB.NET и другие. ASP.NET отличается от простого HTML тем, что сервер выполняет код и отправляет результаты клиенту, позволяя создавать интерактивные и динамически обновляемые веб-страницы. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Какие типы данных можно использовать у Dictionary в качестве ключа? В C# ключ (TKey) в Dictionary<TKey, TValue> должен быть уникальным и поддерживать сравнение. Лучше всего использовать неизменяемые (immutable) типы, такие как: Примитивные типы (int, string, char, bool, Guid, enum) Кортежи (Tuple, ValueTuple) Неизменяемые структуры (struct, если переопределён Equals и GetHashCode) 🚩Какие типы подходят в качестве ключа? Числовые типы (int, double, long)
var dict = new Dictionary<int, string>
{
    {1, "Один"},
    {2, "Два"}
};
Console.WriteLine(dict[1]); // Вывод: Один
string (лучший выбор)
var dict = new Dictionary<string, int>
{
    {"apple", 10},
    {"banana", 5}
};
Console.WriteLine(dict["apple"]); // 10
Guid (уникальные идентификаторы)
var dict = new Dictionary<Guid, string>
{
    {Guid.NewGuid(), "User1"},
    {Guid.NewGuid(), "User2"}
};
enum (хороший вариант)
enum Status { New, Processing, Completed }

var dict = new Dictionary<Status, string>
{
    {Status.New, "Заказ создан"},
    {Status.Processing, "Заказ в обработке"}
};
Можно использовать несколько значений в качестве ключа:
var dict = new Dictionary<(int, string), string>
{
    {(1, "apple"), "Красное яблоко"},
    {(2, "banana"), "Жёлтый банан"}
};
Console.WriteLine(dict[(1, "apple")]); // Красное яблоко
🚩Какие типы нельзя использовать в качестве ключа? List<T> (и другие изменяемые коллекции)
var dict = new Dictionary<List<int>, string>(); // Ошибка при использовании в качестве ключа!
class, если не переопределён Equals и GetHashCode
class Person { public string Name; }
var dict = new Dictionary<Person, string>(); // Плохо!
Нужно переопределить Equals и GetHashCode
class Person
{
    public string Name { get; }

    public Person(string name) => Name = name;

    public override bool Equals(object? obj)
    {
        return obj is Person other && Name == other.Name;
    }

    public override int GetHashCode() => Name.GetHashCode();
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое String? String в C# — это класс, представляющий неизменяемую последовательность символов. Каждый раз, когда строка изменяется, создаётся новый объект String, а старый объект остаётся в памяти до сборки мусора. Строки поддерживают методы для работы с текстом, такие как конкатенация, сравнение и поиск подстрок. Так как строки неизменяемы, для частых изменений строк предпочтительнее использовать StringBuilder. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤖 Топ 4 ИИ-сервиса, которые освободят тебе 30 часов в неделю. Бесплатно + без регистрации Попробовать можно тут 👉 t.me/vist
🤖 Топ 4 ИИ-сервиса, которые освободят тебе 30 часов в неделю. Бесплатно + без регистрации Попробовать можно тут 👉 t.me/vistehno

🤔 Что такое GVT? Это аббревиатура, которая может иметь разные значения в зависимости от контекста. В программировании и IT чаще всего GVT используется в специфических областях. 🚩Global Virtual Time (Глобальное виртуальное время) Это концепция, используемая в распределённых системах и параллельных вычислениях для синхронизации процессов. GVT отображает минимальное время, до которого все события в системе уже обработаны. 🟠Симуляторы дискретного времени например, при моделировании сетей или физических систем. 🟠Алгоритмы для снятия состояния Или управления памятью (garbage collection). Пример Представьте систему, где несколько процессов выполняются параллельно, обрабатывая события с определённой меткой времени. GVT помогает определить минимальную временную точку, до которой можно гарантировать, что все процессы завершили свою работу. 🚩Google Virtual Tables В контексте баз данных и SQL, GVT может использоваться как обозначение для виртуальных таблиц, предоставляемых Google (например, в Google BigQuery). Пример Если вы работаете с Google BigQuery, виртуальные таблицы используются для создания временных представлений данных, которые могут быть обработаны SQL-запросами. 🚩Generic Virtualization Technology Термин, связанный с виртуализацией оборудования. Например, в контексте графических процессоров GVT может обозначать технологию, позволяющую виртуализировать графический процессор (GPU) для использования несколькими виртуальными машинами. 🟠Серверы с виртуальными машинами Которые требуют доступа к ускоренной графике. 🟠Облачные сервисы Предоставляющие GPU как услугу. Пример Intel GVT-g — технология, которая позволяет нескольким виртуальным машинам совместно использовать один GPU, обеспечивая каждому виртуальному окружению необходимую производительность. Ставь 👍 и забирай 📚 Базу знаний

🤔 Какие различия между абстрактными и обычными методами? - Абстрактный метод: - Не имеет реализации. - Должен быть переопределён в наследнике. - Объявляется только внутри абстрактного класса. - Обычный метод: - Имеет реализацию. - Может вызываться напрямую. - Может быть переопределён или нет — по ситуации. Абстрактный метод задаёт обязательную реализацию, а обычный — реальную логику. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Какие тесты бывают? 🚩Виды 🟠Юнит-тесты Предназначены для проверки отдельных компонентов или модулей приложения в изоляции. Они помогают убедиться, что отдельные функции или методы работают правильно. Цель: Проверка логики отдельных методов или классов. Инструменты: xUnit, NUnit, MSTest.
using Xunit;

public class CalculatorTests
{
    [Fact]
    public void Add_SimpleValues_ReturnsSum()
    {
        var calculator = new Calculator();
        var result = calculator.Add(2, 3);
        Assert.Equal(5, result);
    }
}

public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}
🟠Интеграционные тесты Проверяют взаимодействие между различными компонентами системы, убеждаясь, что они корректно работают вместе. Цель: Проверка взаимодействия между модулями. Инструменты: xUnit, NUnit, MSTest, плюс дополнительные библиотеки для тестирования баз данных или HTTP-запросов.
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;

public class IntegrationTests
{
    private readonly HttpClient _client;

    public IntegrationTests()
    {
        var appFactory = new CustomWebApplicationFactory<Startup>();
        _client = appFactory.CreateClient();
    }

    [Fact]
    public async Task Get_EndpointReturnsSuccessAndCorrectContentType()
    {
        var response = await _client.GetAsync("/api/values");
        response.EnsureSuccessStatusCode();
        Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
    }
}
🟠Функциональные тесты Проверяют, что приложение выполняет свои функции в соответствии с требованиями. Эти тесты проверяют конкретные сценарии использования. Цель: Проверка функциональности приложения на уровне пользователя. Инструменты: Selenium, Playwright, Cypress.
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using Xunit;

public class UiTests
{
    [Fact]
    public void LoadPage_CheckTitle()
    {
        using (IWebDriver driver = new ChromeDriver())
        {
            driver.Navigate().GoToUrl("https://example.com");
            Assert.Equal("Example Domain", driver.Title);
        }
    }
}
🟠Системные тесты Проверяют приложение в целом, включая взаимодействие с внешними системами и проверку всех требований. Цель: Проверка всей системы в интегрированном виде. Инструменты: JUnit, TestNG для Java, или те же инструменты, что и для функциональных тестов. 🟠Приемочные тесты Проводятся для проверки, что приложение соответствует требованиям и готово к использованию клиентом или конечным пользователем. Цель: Подтверждение соответствия приложения требованиям. Инструменты: Cucumber, SpecFlow (для BDD). 🟠Регрессионные тесты Проверяют, что недавние изменения в коде не нарушили существующую функциональность. Цель: Убедиться, что новые изменения не привели к новым багам. Инструменты: Все инструменты для юнит-тестирования и функционального тестирования. 🟠Нагрузочные тесты Проверяют, как приложение ведет себя под нагрузкой, например, при большом количестве одновременных пользователей или операций. Цель: Оценка производительности и устойчивости приложения под нагрузкой. Инструменты: JMeter, Gatling, Apache Bench. Ставь 👍 и забирай 📚 Базу знаний

🤔 В чём отличие реализации взаимодействия с БД через ORM и нативный SQL? - ORM (Object-Relational Mapping): - Автоматически связывает объекты и таблицы. - Позволяет писать код на C#/Java вместо SQL. - Повышает читаемость, уменьшает boilerplate. - Меньше контроля над SQL. - Нативный SQL: - Полный контроль над запросами. - Производительность выше в сложных сценариях. - Требует ручной работы с соединениями, маппингом, транзакциями. Выбор зависит от проекта: ORM — быстрее в разработке, SQL — гибче и мощнее при оптимизации. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Как браузер отправляет запрос и получает ответ от API? Когда браузер отправляет запрос и получает ответ от API, это включает несколько шагов, которые следуют HTTP-протоколу. Этот процесс включает в себя создание и отправку HTTP-запроса, обработку на сервере и получение HTTP-ответа. 🚩Отправка запроса 🟠Инициация запроса Обычно запрос инициируется через JavaScript с использованием встроенных функций, таких как XMLHttpRequest, fetch или сторонние библиотеки, такие как Axios.
   fetch('https://api.example.com/data', {
       method: 'GET',
       headers: {
           'Content-Type': 'application/json',
           'Authorization': 'Bearer token'
       }
   })
   .then(response => response.json())
   .then(data => console.log(data))
   .catch(error => console.error('Error:', error));
   
🟠Формирование HTTP-запроса Метод: Указывает тип запроса (например, GET, POST, PUT, DELETE). URL: Указывает на какой URL отправляется запрос. Заголовки (Headers): Включают информацию о типе содержимого, авторизации и других метаданных. Тело (Body): Содержит данные, которые отправляются с запросом (для методов POST, PUT и PATCH). 🟠Отправка запроса Браузер использует сетевые протоколы для отправки сформированного HTTP-запроса на указанный сервер через интернет. 🚩Обработка запроса на сервере 1⃣Получение запроса Сервер получает HTTP-запрос. 2⃣Обработка запроса Сервер обрабатывает запрос, выполняя соответствующие действия, такие как чтение данных из базы данных, выполнение логики приложения или взаимодействие с другими сервисами. 3⃣Формирование ответа Статус код (Status Code): Указывает результат обработки запроса (например, 200 OK, 404 Not Found, 500 Internal Server Error). Заголовки (Headers): Могут включать метаданные о содержимом ответа, кэшировании и других параметрах. Тело (Body): Содержит данные, которые отправляются обратно клиенту, часто в формате JSON или XML.
   HTTP/1.1 200 OK
   Content-Type: application/json
   Content-Length: 85

   {
       "id": 1,
       "name": "Example",
       "description": "This is an example response"
   }
   
🚩Получение ответа 1⃣Получение ответа Браузер получает HTTP-ответ от сервера. 2⃣Обработка ответа Статус код: Браузер или JavaScript-код проверяет статус код, чтобы определить, был ли запрос успешным. Заголовки: Заголовки могут быть использованы для получения дополнительной информации о ответе. Тело: Браузер разбирает тело ответа, если это необходимо, например, преобразует JSON-данные в объект JavaScript. 3⃣Использование данных Полученные данные могут быть использованы в приложении для обновления интерфейса пользователя, хранения в локальном хранилище или выполнения других действий. 🚩Пример полного цикла запроса и ответа Отправка запроса
fetch('https://api.example.com/data', {
    method: 'GET',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer token'
    }
})
.then(response => {
    if (!response.ok) {
        throw new Error('Network response was not ok ' + response.statusText);
    }
    return response.json();
})
.then(data => {
    console.log('Data received:', data);
    // Используем данные для обновления UI или других целей
})
.catch(error => {
    console.error('There has been a problem with your fetch operation:', error);
});
Ставь 👍 и забирай 📚 Базу знаний

🤔 Какие типы HTTP-запросов бывают и где в них передаются данные? 1. GET: данные передаются в URL как параметры. 2. POST: данные передаются в теле запроса. 3. PUT и PATCH: обновляют данные, передавая их в теле запроса. 4. DELETE: удаляет ресурс, данные могут передаваться в URL или теле. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое 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 гарантирует, что только один поток может исполнять определенный блок кода, работающий с критическими ресурсами, в любой момент времени. Ставь 👍 и забирай 📚 Базу знаний

Современная магистратура от Центрального университета Хочешь развиваться в сфере ИТ и получить фундаментальные знания с практ
Современная магистратура от Центрального университета Хочешь развиваться в сфере ИТ и получить фундаментальные знания с практикой? Поступай в магистратуру Центрального университета! - 4 офлайн программы по востребованным направлениям ИТ - Онлайн-программа по машинному обучению - 300 мест с грантами до 1,2 млн руб. - Вечерние занятия и учеба по выходным — удобно совмещать с работой - Обучение по модели STEM-образования: на стыке науки, технологий и бизнеса - Возможность стажировок и трудоустройства в ведущих компаниях - Государственный диплом за 2 года Магистратура в Центральном университете — это современный подход к образованию, сильный преподавательский состав и актуальные кейсы от индустрии. Оставляй заявку на грант уже сейчас! Подать заявку #реклама 16+ apply.centraluniversity.ru О рекламодателе

🤔 Что бывает, когда количества подключений не хватает? Когда лимит подключений к базе данных превышен: 1. Запросы начинают блокироваться, вызывая задержки. 2. Сервер может возвращать ошибки подключения. 3. Производительность приложения резко снижается. Решение: увеличить лимит подключений или оптимизировать запросы. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое cancellation token в многопоточности? CancellationToken в C# используется для координации отмены между потоками. Это механизм, позволяющий запрашивать отмену операции (например, задачи Task или асинхронного метода), не прерывая поток принудительно. 🚩Зачем нужен `CancellationToken`? В многопоточных или асинхронных операциях бывает необходимо отменить выполнение кода, например: Пользователь отменил загрузку файла. Истек тайм-аут выполнения операции. Нужно прервать выполнение нескольких связанных задач. 🚩Как работает `CancellationToken`? 🟠Создание `CancellationTokenSource` Источник токена (CancellationTokenSource) управляет токеном (CancellationToken), который передаётся в задачи. 🟠Передача токена в выполняемую операцию Код регулярно проверяет cancellationToken.IsCancellationRequested, чтобы определить, нужно ли остановиться. 🟠Запрос на отмену Если вызывается cts.Cancel(), все методы, использующие этот токен, получают сигнал об отмене. 🚩Пример использования
using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        using var cts = new CancellationTokenSource();

        // Отменяем операцию через 3 секунды
        cts.CancelAfter(3000);

        try
        {
            await DoWorkAsync(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Операция отменена!");
        }
    }

    static async Task DoWorkAsync(CancellationToken cancellationToken)
    {
        for (int i = 0; i < 10; i++)
        {
            cancellationToken.ThrowIfCancellationRequested(); // Проверка отмены

            Console.WriteLine($"Работаем... {i}");
            await Task.Delay(1000, cancellationToken); // Ожидание с проверкой отмены
        }
    }
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Использование интерфейса уже является Dependency Inversion? Да, использование интерфейса поддерживает принцип Dependency Inversion, так как позволяет объектам зависеть от абстракций, а не от конкретных реализаций. Это уменьшает связанность и повышает гибкость кода. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Какие есть способы (протоколы) обмена данными между сервером и клиентом? При взаимодействии клиента и сервера используются различные*протоколы обмена данными, в зависимости от задачи, скорости, надежности и реального времени. 🚩HTTP(S) – стандартный протокол веба Клиент (браузер, мобильное приложение) делает запрос к серверу. Сервер отправляет ответ с данными (HTML, JSON, XML). Использует методы: GET, POST, PUT, DELETE и т. д.
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data));
🚩WebSocket – двусторонняя связь в реальном времени Клиент устанавливает постоянное соединение с сервером. Сервер и клиент могут отправлять друг другу данные в любое время. Используется для чата, онлайн-игр, бирж, обновлений в реальном времени.
const socket = new WebSocket('wss://example.com/socket');

socket.onopen = () => socket.send('Привет, сервер!');
socket.onmessage = event => console.log('Сообщение от сервера:', event.data);
🚩SSE (Server-Sent Events) – поток данных от сервера Клиент делает HTTP-запрос, но соединение не закрывается. Сервер постепенно отправляет данные в виде событий (event-stream). Используется для новостей, биржевых данных, уведомлений.
const eventSource = new EventSource('/events');

eventSource.onmessage = event => console.log('Новое сообщение:', event.data);
🚩gRPC – быстрый RPC поверх HTTP/2 Клиент вызывает удаленные методы напрямую как обычные функции. Работает на HTTP/2, использует бинарный формат Protocol Buffers (быстрее, чем JSON). Используется для высокопроизводительных API, микросервисов.
import grpc
import my_service_pb2
import my_service_pb2_grpc

channel = grpc.insecure_channel('localhost:50051')
stub = my_service_pb2_grpc.MyServiceStub(channel)
response = stub.MyMethod(my_service_pb2.MyRequest(name="Alice"))
print(response.message)
🚩MQTT – лёгкий протокол для IoT Работает по модели издатель/подписчик. Клиент подписывается на тему (topic) и получает сообщения, когда кто-то публикует данные. Используется для умных устройств, датчиков, IoT.
const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://broker.hivemq.com');

client.on('connect', () => {
    client.subscribe('myTopic');
    client.publish('myTopic', 'Привет, MQTT!');
});

client.on('message', (topic, message) => {
    console.log(`Сообщение из ${topic}: ${message.toString()}`);
});
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что значит, что система является RESTful? Это система, реализующая архитектурный стиль REST (Representational State Transfer). Это означает: - Используются HTTP-методы как команды (GET, POST, PUT, DELETE). - Ресурсы имеют уникальные URI. - Коммуникация без состояния (stateless). - Возможна кэшируемость. - Данные передаются в виде представлений ресурса (обычно JSON/XML).ксте онлайн Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

📺 Уникальная база IT собеседований 456+ реальных собеседований на программиста, тестировщика, аналитика и прочие IT профы. Е
📺 Уникальная база IT собеседований 456+ реальных собеседований на программиста, тестировщика, аналитика и прочие IT профы. Есть собесы от ведущих компаний: Сбер, Яндекс, ВТБ, Тинькофф, Озон, Wildberries и т.д. 🎯 Переходи по ссылке и присоединяйся к базе, чтобы прокачать свои шансы на успешное трудоустройство!

🤔 В каком случае использовать интерфейс, в каком абстрактный класс? Выбор между интерфейсом и абстрактным классом в 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");
}
Ставь 👍 и забирай 📚 Базу знаний

C# | Вопросы собесов - Telegram 频道 @easy_c_sharp 的统计与分析