C# | Вопросы собесов
5.1K subscribers
36 photos
1 file
989 links
Download Telegram
📌 Что такое групповые делегаты?

💬 Спрашивают в 22% собеседований

Групповые делегаты в C# представляют собой делегаты, которые могут содержать ссылки на несколько методов. Такие делегаты позволяют вызывать несколько методов последовательно в рамках одного вызова делегата. Это часто используется для событий и обратных вызовов (callbacks).

1️⃣ Основные понятия:

1. Делегат — это тип, который представляет ссылку на метод с определенной сигнатурой.
2. Групповой делегат — это делегат, который содержит ссылки на несколько методов и вызывает их по очереди.

2️⃣ Как создаются групповые делегаты:

Объединение делегатов.

Чтобы создать групповой делегат, нужно объединить несколько делегатов с помощью оператора + или метода Delegate.Combine.

Пример:
using System;

public delegate void MyDelegate();

public class Program
{
public static void Method1()
{
Console.WriteLine("Method1");
}

public static void Method2()
{
Console.WriteLine("Method2");
}

public static void Main()
{
MyDelegate del1 = Method1;
MyDelegate del2 = Method2;

// Объединяем делегаты
MyDelegate groupDel = del1 + del2;

// Вызов группового делегата
groupDel();
}
}


Вывод:
Method1
Method2


Удаление делегатов.

Для удаления метода из группового делегата используется оператор - или метод Delegate.Remove.

Пример:
using System;

public delegate void MyDelegate();

public class Program
{
public static void Method1()
{
Console.WriteLine("Method1");
}

public static void Method2()
{
Console.WriteLine("Method2");
}

public static void Main()
{
MyDelegate del1 = Method1;
MyDelegate del2 = Method2;

// Объединяем делегаты
MyDelegate groupDel = del1 + del2;

// Удаляем делегат
groupDel -= del1;

// Вызов группового делегата
groupDel();
}
}


Вывод:
Method2


3️⃣ Использование в событиях:

Групповые делегаты особенно полезны при работе с событиями, где несколько подписчиков могут быть уведомлены об одном и том же событии.

Пример:
using System;

public delegate void Notify(); // делегат для события

public class ProcessBusinessLogic
{
public event Notify ProcessCompleted; // событие

public void StartProcess()
{
Console.WriteLine("Process Started!");
// Какое-то логика процесса...
OnProcessCompleted();
}

protected virtual void OnProcessCompleted()
{
// Если есть подписчики
if (ProcessCompleted != null)
ProcessCompleted.Invoke();
}
}

public class Program
{
public static void Main()
{
ProcessBusinessLogic bl = new ProcessBusinessLogic();
bl.ProcessCompleted += bl_ProcessCompleted; // подписка на событие
bl.ProcessCompleted += bl_ProcessCompleted2; // подписка на событие
bl.StartProcess();
}

public static void bl_ProcessCompleted()
{
Console.WriteLine("Process Completed!");
}

public static void bl_ProcessCompleted2()
{
Console.WriteLine("Process Completed Again!");
}
}


Вывод:
Process Started!
Process Completed!
Process Completed Again!


Заключение:

Групповые делегаты в C# позволяют объединять несколько методов в один делегат и вызывать их последовательно. Они часто используются в событиях для уведомления нескольких подписчиков.

Кратко:

Групповые делегаты в C# позволяют объединять несколько методов в один делегат и вызывать их последовательно. Это полезно для уведомления нескольких подписчиков в событиях.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2🎉1
📌 Что такое Inversion of control и dependency injection?

💬 Спрашивают в 78% собеседований

Inversion of Control (IoC) и Dependency Injection (DI) — это два тесно связанных принципа, используемых для уменьшения зависимостей между компонентами программного обеспечения, что упрощает управление этими зависимостями, их тестирование и поддержку.

1️⃣ Inversion of Control (Инверсия управления)

Это принцип программирования, при котором управление потоком программы передаётся из пользовательского кода во внешнюю библиотеку или фреймворк. В традиционном программировании пользовательский код, который вы пишете, вызывает библиотеки, когда нуждается в выполнении какой-либо функциональности. При использовании IoC библиотека вызывает ваш код. Это обеспечивает большую гибкость и упрощает расширение функциональности и тестирование, так как уменьшает зависимость кода от конкретной реализации задач.

IoC часто реализуется с помощью таких паттернов, как Dependency Injection, Event, Strategy.

2️⃣ Dependency Injection (Внедрение зависимостей)

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

Пример:
public interface ILogger
{
void Log(string message);
}

public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}

public class Application
{
private readonly ILogger _logger;

// Внедрение зависимости через конструктор
public Application(ILogger logger)
{
_logger = logger;
}

public void Run()
{
_logger.Log("Приложение запущено");
}
}

// Где-то в другом месте приложения
ILogger logger = new ConsoleLogger();
Application app = new Application(logger);
app.Run();


В этом примере Application зависит от абстракции ILogger. Вместо того чтобы создавать конкретный экземпляр ConsoleLogger внутри Application, мы передаём его через конструктор, что позволяет легко заменить реализацию логгера без изменения кода класса Application.

IoC — это более широкий принцип проектирования, который гласит: не ваш код должен контролировать поток выполнения программы, а некая внешняя сущность. DI — это конкретный способ достижения IoC, когда зависимости объектов предоставляются извне, а не создаются самими объектами.

Инверсия управления — это когда ваш код не управляет потоком выполнения, а подчиняется внешнему "руководителю". Внедрение зависимостей — это когда ваш код не создает то, что ему нужно для работы сам, а получает это "снаружи".

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
📌 Какие преимущества у LinQ?

💬 Спрашивают в 22 % собеседований

LINQ (Language Integrated Query) — это компонент .NET Framework, который добавляет возможности запроса данных из различных источников (таких как коллекции, базы данных, XML и другие) прямо в код C#. LINQ обеспечивает единообразный способ работы с данными, позволяя использовать одни и те же методы для различных типов данных. Вот основные преимущества LINQ:

1️⃣ Унифицированный синтаксис:
LINQ предоставляет единый и последовательный способ работы с данными, будь то массивы, списки, базы данных или XML. Это снижает необходимость изучения различных API для работы с разными источниками данных.
    // Пример запроса к массиву
int[] numbers = { 1, 2, 3, 4, 5 };
var evenNumbers = from num in numbers
where num % 2 == 0
select num;


2️⃣ Читабельность кода:
Запросы LINQ легко читаются и понимаются, так как они используют знакомые конструкты языка программирования. Это упрощает поддержку и развитие кода.
    // Пример запроса к списку объектов
List<Person> people = GetPeopleList();
var adults = from person in people
where person.Age >= 18
select person;


3️⃣ Типобезопасность:
LINQ предоставляет строгую проверку типов на этапе компиляции, что помогает избежать многих ошибок, связанных с неправильным использованием типов данных. Это делает код более надежным.
    // Пример использования LINQ с типизированными данными
var adults = people.Where(p => p.Age >= 18);


4️⃣ Упрощение сложных запросов:
LINQ позволяет легко составлять сложные запросы, которые могут включать сортировку, группировку и объединение данных. Это позволяет сосредоточиться на логике запроса, а не на низкоуровневых деталях его выполнения.
    // Пример группировки данных с использованием LINQ
var groupedPeople = from person in people
group person by person.Age into ageGroup
select new { Age = ageGroup.Key, People = ageGroup };


5️⃣ Ленивые вычисления:
LINQ поддерживает ленивые вычисления, что означает, что данные не извлекаются из источника до тех пор, пока это не потребуется. Это может существенно повысить производительность, особенно при работе с большими объемами данных.
    // Пример ленивых вычислений
var query = people.Where(p => p.Age >= 18); // Запрос еще не выполнен
foreach (var person in query)
{
Console.WriteLine(person.Name); // Запрос выполняется здесь
}


6️⃣ Поддержка различных источников данных:
LINQ работает с различными источниками данных, включая массивы, списки, базы данных (через LINQ to SQL или Entity Framework), XML и даже сторонние сервисы.
    // Пример запроса к базе данных с использованием Entity Framework
using (var context = new MyDbContext())
{
var users = from user in context.Users
where user.IsActive
select user;
}


🤔 Краткое резюме:

LINQ упрощает работу с данными, делая код более читабельным и типобезопасным, поддерживает различные источники данных и позволяет легко составлять сложные запросы. Это инструмент, который помогает программистам писать более понятный, поддерживаемый и эффективный код.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Какой модификатор доступа в C# делает класс или член доступным только внутри своей сборки?
Anonymous Quiz
1%
public
10%
private
15%
protected
74%
internal
👍4
📌 Garbage collectior что это?

💬 Спрашивают в 22 % собеседований

Garbage Collector (GC) — это механизм управления памятью в среде выполнения .NET, который автоматически освобождает память, занимаемую объектами, которые больше не используются приложением. Это важная часть управления ресурсами в .NET, так как она предотвращает утечки памяти и улучшает общую производительность приложения. Вот основные аспекты работы Garbage Collector и его преимущества:

🤔 Основные функции Garbage Collector

1️⃣ Автоматическое управление памятью:

GC автоматически отслеживает объекты, создаваемые в управляемой куче (managed heap), и освобождает память, занимаемую объектами, которые больше не достижимы или не используются приложением. Это снижает необходимость ручного управления памятью и уменьшает вероятность утечек памяти.

2️⃣ Сборка мусора:

GC выполняет сборку мусора (garbage collection) в несколько этапов:

Маркировка (Marking): GC определяет, какие объекты все еще достижимы и используются.

Очистка (Sweeping): Память, занимаемая недостижимыми объектами, освобождается.

Компактирование (Compacting): Память, занимаемая достижимыми объектами, перемещается для сокращения фрагментации.

3️⃣ Поколения объектов:

Объекты в управляемой куче делятся на поколения (Generation):

Generation 0: Новые объекты, которые недавно созданы. Сборка мусора для этого поколения выполняется чаще.

Generation 1: Объекты, которые пережили хотя бы одну сборку мусора.

Generation 2: Объекты, которые живут достаточно долго и пережили несколько сборок мусора.

Такое разделение помогает оптимизировать производительность сборки мусора, так как более молодые объекты имеют большую вероятность стать недостижимыми быстрее, чем старые.

4️⃣ Сборка в фоновом режиме:
.NET GC поддерживает сборку мусора в фоновом режиме, что позволяет минимизировать паузы в работе приложения за счет выполнения сборки мусора параллельно с основной работой приложения.

🤔 Преимущества Garbage Collector

1️⃣ Простота использования:
Программисты могут сосредоточиться на логике приложения, не заботясь о ручном управлении памятью, что упрощает разработку и снижает вероятность ошибок.

2️⃣ Предотвращение утечек памяти:
GC автоматически освобождает память, занимаемую недостижимыми объектами, что помогает предотвратить утечки памяти, которые могут привести к снижению производительности и нестабильности приложения.

3️⃣ Оптимизация использования памяти:
GC периодически выполняет компактирование памяти, что снижает фрагментацию и улучшает производительность приложения.

🤔 Пример работы Garbage Collector

Рассмотрим пример создания объектов в C# и как GC их обрабатывает:
class Program
{
static void Main()
{
// Создание объектов
for (int i = 0; i < 100; i++)
{
MyClass obj = new MyClass();
}

// Вызов сборки мусора вручную (обычно не рекомендуется)
GC.Collect();
GC.WaitForPendingFinalizers();
}
}

class MyClass
{
~MyClass()
{
// Финализатор, который вызывается перед удалением объекта
Console.WriteLine("Объект удален");
}
}


В этом примере создается 100 объектов класса MyClass. Когда они выходят из области видимости, GC может освободить память, занимаемую этими объектами.

🤔 Краткое резюме:

Garbage Collector автоматически управляет памятью, освобождая память, занимаемую неиспользуемыми объектами. Это упрощает разработку, предотвращает утечки памяти и улучшает производительность приложения.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31
🤔 Какое ключевое слово используется для определения асинхронного метода в C#?
Anonymous Quiz
94%
async
4%
await
1%
asyncronous
0%
parallel
👍2
📌 Зачем сделали ref & out для ссылочных типов?

💬 Спрашивают в 22% собеседований

В C# ключевые слова ref и out используются для передачи аргументов по ссылке, что позволяет методам изменять значения этих аргументов. Эти механизмы полезны как для значимых типов (структур), так и для ссылочных типов (объектов). Давайте рассмотрим более детально, зачем и как их используют для ссылочных типов.

🤔 Зачем нужны `ref` и `out` для ссылочных типов?

🤔 `ref`

Изменение самого объекта: С помощью ref можно передавать ссылочные типы таким образом, чтобы метод мог изменять саму ссылку, то есть ссылаться на другой объект.

Пример: Представим себе метод, который принимает объект и может его заменить новым объектом.

🤔 `out`

Передача непроинициализированных объектов: Ключевое слово out позволяет передавать аргумент, который не обязательно должен быть инициализирован до вызова метода. Метод, принимающий out аргумент, обязан присвоить ему значение до завершения работы.

Пример: Метод, который инициализирует и возвращает объект.

🤔 Как используются `ref` и `out`?

🤔 Пример использования `ref`
class Program
{
static void ChangeReference(ref MyClass obj)
{
obj = new MyClass { Value = 20 };
}

static void Main()
{
MyClass myObj = new MyClass { Value = 10 };
ChangeReference(ref myObj);
Console.WriteLine(myObj.Value); // Output: 20
}
}

class MyClass
{
public int Value { get; set; }
}


В этом примере ref позволяет методу ChangeReference изменить ссылку myObj на новый объект MyClass.

🤔 Пример использования `out`
class Program
{
static void InitializeObject(out MyClass obj)
{
obj = new MyClass { Value = 30 };
}

static void Main()
{
MyClass myObj;
InitializeObject(out myObj);
Console.WriteLine(myObj.Value); // Output: 30
}
}

class MyClass
{
public int Value { get; set; }
}


В этом примере метод InitializeObject использует out для создания и инициализации нового объекта MyClass.

🤔 Почему это нужно?

1️⃣ Гибкость: ref и out добавляют гибкости при работе с методами, позволяя им изменять ссылки на объекты или создавать и возвращать новые объекты.

2️⃣ Оптимизация: Эти механизмы могут быть полезны для оптимизации, когда необходимо избежать лишнего копирования данных, особенно при работе с большими объектами.

3️⃣ Логика инициализации: out полезен для методов, которые должны вернуть несколько значений или инициализировать объекты, которые не могут быть инициализированы заранее.

🤔 Краткий ответ

ref и out используются для передачи объектов по ссылке, что позволяет методам изменять ссылки на объекты или инициализировать их. Это добавляет гибкости и позволяет оптимизировать работу с памятью.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Какое пространство имён в C# обычно используется для работы с веб-запросами?
Anonymous Quiz
20%
System.Net
29%
System.Web
47%
System.Http
🤯6
📌 Какие бывают типы данных?

💬 Спрашивают в 22% собеседований

В C# существует множество различных типов данных, которые можно разделить на две основные категории: значимые типы (value types) и ссылочные типы (reference types). Рассмотрим каждую из этих категорий и их подтипы.

🤔 Значимые типы (Value Types)

Значимые типы хранят данные непосредственно в своей памяти. Они обычно располагаются в стеке и имеют фиксированный размер. К значимым типам относятся:

1️⃣ Простые типы (Simple Types)

Числовые типы

Целочисленные типы:

byte (8 бит)

sbyte (8 бит)

short (16 бит)

ushort (16 бит)

int (32 бита)

uint (32 бита)

long (64 бита)

ulong (64 бита)

Вещественные типы:

float (32 бита)

double (64 бита)

Десятичный тип:

decimal (128 бит)

Логический тип

bool (1 бит, значения true или false)

Символьный тип

char (16 бит, символы в формате Unicode)

2️⃣ Структуры (Structs)

Пользовательские типы, которые могут содержать поля, свойства и методы.

Пример: struct Point { public int X; public int Y; }

3️⃣ Перечисления (Enums)

Специальные типы, представляющие набор именованных констант.

Пример: enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }

4️⃣ Nullable Types

Типы, которые могут принимать значение null.

Пример: int?, double?

🤔 Ссылочные типы (Reference Types)

Ссылочные типы хранят ссылки на данные, которые размещаются в куче. К ссылочным типам относятся:

1️⃣ Классы (Classes)

Основные объекты в C#, могут содержать поля, свойства, методы и события.

Пример: class Person { public string Name; public int Age; }

2️⃣ Интерфейсы (Interfaces)

Определяют контракт, который должны реализовать классы.

Пример: interface IMovable { void Move(); }

3️⃣ Массивы (Arrays)

Коллекции однотипных элементов.

Пример: int[] numbers = new int[5];

4️⃣ Делегаты (Delegates)

Типы, которые представляют собой ссылки на методы.

Пример: delegate void Process(int value);

5️⃣ Строки (Strings)

Непосредственно представляют собой последовательность символов.

Пример: string message = "Hello, World!";

6️⃣ Записи (Records)

Новый тип в C# 9.0, предназначенный для неизменяемых объектов.

Пример: record Person(string Name, int Age);

🤔 Примеры и использование

🤔 Значимые типы
int a = 5;
float b = 3.14f;
bool isTrue = true;
char letter = 'A';


🤔 Ссылочные типы
string message = "Hello, World!";
Person person = new Person { Name = "Alice", Age = 30 };

int[] numbers = new int[] { 1, 2, 3, 4, 5 };


🤔 Краткий ответ

Типы данных в C# делятся на значимые и ссылочные. Значимые типы хранят данные непосредственно, а ссылочные типы хранят ссылки на данные в памяти.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
📌 Какова концепция сборки мусора в С#?

💬 Спрашивают в 22% собеседований

Сборка мусора (Garbage Collection, GC) в C# — это автоматический процесс управления памятью, который освобождает память, занятую объектами, которые больше не используются приложением. Этот механизм помогает разработчикам избежать ошибок, связанных с управлением памятью вручную, таких как утечки памяти и неправильное использование освобожденных ресурсов. Давайте рассмотрим концепцию сборки мусора в C# подробнее.

🤔 Основные концепции сборки мусора

1️⃣ Управляемая куча (Managed Heap):

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

2️⃣ Корни (Roots):

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

3️⃣ Алгоритм маркировки и сжатия (Mark-and-Compact):

GC использует алгоритм маркировки и сжатия для определения объектов, которые больше не используются. Сначала он помечает все доступные объекты (те, до которых можно добраться из корней), а затем удаляет все непомеченные объекты, освобождая их память.

4️⃣ Поколения (Generations):

Память управляемой кучи разделена на три поколения: поколение 0, поколение 1 и поколение 2. Это позволяет оптимизировать процесс сборки мусора:

Поколение 0: Содержит новые объекты. Сборка мусора здесь происходит чаще всего, так как большинство объектов живут недолго.

Поколение 1: Содержит объекты, которые пережили одну сборку мусора.

Поколение 2: Содержит объекты, которые пережили несколько сборок мусора. Сборка мусора здесь происходит реже всего, так как такие объекты считаются долгоживущими.

🤔 Этапы сборки мусора

1️⃣ Инициализация сборки мусора:

Когда выделяется новая память и управляемая куча достигает определенного порога, запускается процесс сборки мусора.

2️⃣ Маркировка (Mark):

GC проходит по всем корням и помечает все объекты, которые могут быть достигнуты.

3️⃣ Удаление (Sweep):

После маркировки все непомеченные объекты считаются недоступными и могут быть удалены.

4️⃣ Сжатие (Compact):

Для улучшения производительности и уменьшения фрагментации памяти, сборщик мусора может переместить оставшиеся объекты, чтобы освободить блоки памяти.

🤔 Пример кода с использованием сборки мусора
class Program
{
static void Main()
{
for (int i = 0; i < 1000; i++)
{
CreateObject();
}

// Явный вызов сборщика мусора (не рекомендуется для обычного использования)
GC.Collect();
}

static void CreateObject()
{
MyClass obj = new MyClass();
// Объект obj будет собран сборщиком мусора, когда он больше не будет использоваться
}
}

class MyClass
{
// Поля и методы класса
}


🤔 Краткий ответ

Сборка мусора в C# автоматически управляет памятью, освобождая её от объектов, которые больше не нужны. Она помечает используемые объекты и удаляет те, что не используются, что помогает избежать утечек памяти и ошибок управления памятью.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
📌 Какие есть виды полиморфизмов?

💬 Спрашивают в 22% собеседований

Полиморфизм в объектно-ориентированном программировании (ООП) — это способность объектов разного типа обрабатывать данные через единый интерфейс. В C# существует несколько видов полиморфизма, которые можно разделить на две основные категории: компиляторный (статический) полиморфизм и временный (динамический) полиморфизм. Рассмотрим каждый из них более подробно.

🤔 Компиляторный (статический) полиморфизм

Этот тип полиморфизма определяется на этапе компиляции. К нему относятся:

1️⃣ Перегрузка методов (Method Overloading):

Это возможность создавать несколько методов с одним и тем же именем, но с разными параметрами (типами и/или количеством параметров).

Пример:
     class MathOperations
{
public int Add(int a, int b)
{
return a + b;
}

public double Add(double a, double b)
{
return a + b;
}
}


2️⃣ Перегрузка операторов (Operator Overloading):

Позволяет определять поведение стандартных операторов (например, +, -, *, /) для пользовательских типов (классов или структур).

Пример:
     class Complex
{
public double Real { get; set; }
public double Imaginary { get; set; }

public static Complex operator +(Complex c1, Complex c2)
{
return new Complex { Real = c1.Real + c2.Real, Imaginary = c1.Imaginary + c2.Imaginary };
}
}


🤔 Временный (динамический) полиморфизм

Этот тип полиморфизма определяется на этапе выполнения программы. К нему относятся:

1️⃣ Переопределение методов (Method Overriding):

Позволяет подклассу предоставлять специфическую реализацию метода, который уже определен в его суперклассе.

Использует ключевые слова virtual в базовом классе и override в производном классе.

Пример:
     class Animal
{
public virtual void MakeSound()
{
Console.WriteLine("Animal sound");
}
}

class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("Bark");
}
}


2️⃣ Интерфейсы (Interfaces):

Позволяют разным классам реализовывать одно и то же поведение через контракт (интерфейс).

Пример:
     interface IShape
{
void Draw();
}

class Circle : IShape
{
public void Draw()
{
Console.WriteLine("Drawing Circle");
}
}

class Square : IShape
{
public void Draw()
{
Console.WriteLine("Drawing Square");
}
}


🤔 Примеры использования полиморфизма

🤔 Перегрузка методов (статический полиморфизм)
class Printer
{
public void Print(string message)
{
Console.WriteLine(message);
}

public void Print(int number)
{
Console.WriteLine(number);
}
}

class Program
{
static void Main()
{
Printer printer = new Printer();
printer.Print("Hello, world!");
printer.Print(123);
}
}


🤔 Переопределение методов (динамический полиморфизм)
class Program
{
static void Main()
{
Animal myDog = new Dog();
myDog.MakeSound(); // Output: Bark
}
}


🤔 Интерфейсы (динамический полиморфизм)
class Program
{
static void Main()
{
IShape circle = new Circle();
IShape square = new Square();

circle.Draw(); // Output: Drawing Circle
square.Draw(); // Output: Drawing Square
}
}


🤔 Краткий ответ

Полиморфизм в C# бывает двух видов: статический и динамический. Статический включает перегрузку методов и операторов, а динамический включает переопределение методов и использование интерфейсов. Полиморфизм позволяет использовать единый интерфейс для работы с объектами разных типов.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍3🤔1
📌 Какие есть принципы SOLID?

💬 Спрашивают в 22% собеседований

Принципы SOLID — это пять основных принципов объектно-ориентированного проектирования и программирования, которые помогают создавать гибкие и поддерживаемые системы:

1️⃣ S - Single Responsibility Principle (Принцип единственной ответственности)

2️⃣ O - Open/Closed Principle (Принцип открытости/закрытости)

3️⃣ L - Liskov Substitution Principle (Принцип подстановки Барбары Лисков)

4️⃣ I - Interface Segregation Principle (Принцип разделения интерфейса)

5️⃣ D - Dependency Inversion Principle (Принцип инверсии зависимостей)

1️⃣ Принцип единственной ответственности (Single Responsibility Principle)

Каждый класс должен иметь одну задачу и только одну причину для изменения.

Упрощает понимание, сопровождение и тестирование кода.

Пример:
public class Report
{
public string Text { get; set; }

public void PrintReport()
{
// Логика печати отчета
}
}

public class ReportSaver
{
public void SaveToFile(Report report, string filePath)
{
// Логика сохранения отчета в файл
}
}


2️⃣ Принцип открытости/закрытости (Open/Closed Principle)

Программные сущности должны быть открыты для расширения, но закрыты для модификации.

Позволяет добавлять новые функции без изменения существующего кода.

Пример:
public abstract class Shape
{
public abstract double Area();
}

public class Circle : Shape
{
public double Radius { get; set; }

public override double Area()
{
return Math.PI * Radius * Radius;
}
}

public class Square : Shape
{
public double Side { get; set; }

public override double Area()
{
return Side * Side;
}
}


3️⃣ Принцип подстановки Барбары Лисков (Liskov Substitution Principle)

Объекты подклассов должны заменять объекты базового класса без нарушения корректности программы.

Обеспечивает корректное использование наследования.

Пример:
public class Bird
{
public virtual void Fly()
{
// Логика полета
}
}

public class Sparrow : Bird
{
public override void Fly()
{
// Логика полета воробья
}
}

public class Ostrich : Bird
{
public override void Fly()
{
throw new NotImplementedException();
}
}


Здесь принцип нарушен, так как страус не может летать. Лучше не наследовать страуса от класса Bird, если метод Fly не применим ко всем подклассам.

4️⃣ Принцип разделения интерфейса (Interface Segregation Principle)

Клиенты не должны зависеть от интерфейсов, которые они не используют.

Улучшает модульность и уменьшает зависимость между компонентами.

Пример:
public interface IPrinter
{
void Print();
}

public interface IScanner
{
void Scan();
}

public class MultiFunctionPrinter : IPrinter, IScanner
{
public void Print()
{
// Логика печати
}

public void Scan()
{
// Логика сканирования
}
}

public class SimplePrinter : IPrinter
{
public void Print()
{
// Логика печати
}
}


5️⃣ Принцип инверсии зависимостей (Dependency Inversion Principle)

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

Улучшает тестируемость и уменьшает связанность компонентов.

Пример:
public interface IMessageSender
{
void SendMessage(string message);
}

public class EmailSender : IMessageSender
{
public void SendMessage(string message)
{
// Логика отправки email
}
}

public class Notification
{
private readonly IMessageSender _messageSender;

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

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


🤔 Краткий ответ

Принципы SOLID помогают создавать гибкие и поддерживаемые системы. Это принципы единственной ответственности, открытости/закрытости, подстановки Лисков, разделения интерфейса и инверсии зависимостей. Они направлены на улучшение структуры и качества кода.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤯1
📌 Какие минусы у микросервисов?

💬 Спрашивают в 22% собеседований

Микросервисная архитектура предлагает множество преимуществ, таких как независимая разработка и развёртывание компонентов, повышенная масштабируемость и устойчивость к сбоям. Однако, несмотря на все эти плюсы, существуют и некоторые недостатки, которые необходимо учитывать при принятии решения о переходе на микросервисную архитектуру.

1️⃣ Сложность управления

Описание:

Микросервисная архитектура подразумевает наличие множества независимых сервисов, каждый из которых может разрабатываться, развёртываться и масштабироваться отдельно. Это приводит к увеличению числа компонентов, которыми нужно управлять.

Проблемы:

Трудность в мониторинге и управлении состоянием множества сервисов.

Усложнение оркестрации и деплоя (развёртывания).

2️⃣ Межсервисное взаимодействие

Описание:

Микросервисы взаимодействуют друг с другом по сети, используя HTTP, gRPC или другие протоколы.

Проблемы:

Возрастают сетевые задержки и накладные расходы на сериализацию/десериализацию данных.

Возможность возникновения сетевых ошибок, что требует дополнительных механизмов для их обработки и повторных попыток.

3️⃣ Сложность тестирования

Описание:

Тестирование микросервисных систем становится более сложным по сравнению с монолитными приложениями.

Проблемы:

Необходимость тестирования взаимодействий между сервисами.

Сложность воссоздания тестовой среды, которая точно отражает производственную.

4️⃣ Управление данными и консистентность

Описание:

В микросервисной архитектуре каждый сервис может иметь собственную базу данных, что помогает в разделении данных, но создаёт новые проблемы.

Проблемы:

Сложность поддержания консистентности данных между различными сервисами.

Необходимость реализации распределённых транзакций или механизмов компенсации.

5️⃣ Повышенные требования к инфраструктуре

Описание:

Микросервисы часто требуют более сложной инфраструктуры для управления контейнерами, оркестрацией, мониторингом и логированием.

Проблемы:

Увеличение затрат на инфраструктуру и её поддержку.

Необходимость в новых инструментах и технологиях, таких как Kubernetes, для эффективного управления контейнерами.

6️⃣ Организационные сложности

Описание:

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

Проблемы:

Необходимость переквалификации команды разработчиков и операционной команды.

Потребность в новой культуре взаимодействия между командами (DevOps, CI/CD).

🤔 Пример сложностей

Предположим, у нас есть система микросервисов для интернет-магазина. Один микросервис отвечает за управление товарами, другой за обработку заказов, а третий за платежи. В монолитной архитектуре все компоненты находятся в одном приложении, и взаимодействие между ними происходит напрямую через вызовы методов. В микросервисной архитектуре взаимодействие будет происходить через сетевые запросы.

Межсервисное взаимодействие: Если сервис обработки заказов должен получить информацию о товаре, ему нужно сделать сетевой запрос к сервису управления товарами. Это может привести к сетевым задержкам или временным сбоям, если сервис управления товарами недоступен.

Консистентность данных: Когда заказ обрабатывается, сервис заказов и сервис платежей должны быть синхронизированы, чтобы избежать ситуаций, когда заказ оплачен, но не обработан должным образом. Это требует реализации механизмов для поддержания консистентности между этими сервисами.

🤔 Краткий ответ

Микросервисная архитектура может усложнить управление системой, увеличить сетевые задержки, усложнить тестирование и поддержание консистентности данных, повысить требования к инфраструктуре и создать организационные сложности.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍3
🤔 Какой модификатор доступа позволяет доступ к члену класса только изнутри самого класса и производных классов?
Anonymous Quiz
14%
private
74%
protected
10%
internal
1%
public
👍1
📌 Что такое .NET Core?

💬 Спрашивают в 22% собеседований

.NET Core — это кроссплатформенная, высокопроизводительная и модульная среда выполнения, разработанная компанией Microsoft. Она предназначена для создания современных приложений, которые могут быть развёрнуты на различных операционных системах, включая Windows, macOS и Linux. .NET Core является частью более широкой экосистемы .NET и представляет собой значительное развитие по сравнению с традиционным .NET Framework. Рассмотрим основные особенности и компоненты .NET Core подробнее.

🤔 Основные особенности .NET Core

1️⃣ Кроссплатформенность:

.NET Core поддерживает работу на различных операционных системах: Windows, macOS и Linux.

Это позволяет разработчикам писать код, который может быть запущен на любом поддерживаемом устройстве или сервере, без необходимости вносить изменения в код.

2️⃣ Высокая производительность:

.NET Core оптимизирован для высокой производительности и эффективности.

Его использование позволяет создавать высоконагруженные приложения, такие как веб-сервисы и микросервисы.

3️⃣ Модульная архитектура:

.NET Core предоставляет возможность установки только тех пакетов и библиотек, которые необходимы для конкретного приложения.

Это уменьшает объём занимаемого пространства и улучшает управляемость зависимостями.

4️⃣ Открытый исходный код:

Исходный код .NET Core является открытым и доступен на GitHub.

Это способствует прозрачности разработки и позволяет сообществу вносить вклад в улучшение платформы.

5️⃣ Унифицированная платформа:

.NET Core объединяет несколько различных платформ (например, ASP.NET для веб-разработки, Xamarin для мобильной разработки и т.д.) под единым фреймворком.

Это позволяет разработчикам использовать одни и те же инструменты и библиотеки для различных типов приложений.

🤔 Компоненты .NET Core

1️⃣ CLR (Common Language Runtime):

Среда выполнения, которая управляет исполнением .NET приложений. Включает в себя управление памятью, выполнение кода, компиляцию JIT (Just-In-Time) и сборку мусора.

2️⃣ Библиотека классов (Base Class Library, BCL):

Набор библиотек, предоставляющих основные функциональные возможности, такие как работа с файловой системой, сетевое взаимодействие, управление потоками и многое другое.

3️⃣ CLI (Command-Line Interface):

Интерфейс командной строки, который предоставляет инструменты для создания, компиляции и развёртывания приложений .NET Core.

4️⃣ SDK (Software Development Kit):

Набор инструментов и библиотек для разработки приложений на .NET Core. Включает компиляторы, библиотеку классов и инструменты для работы с проектами.

5️⃣ ASP.NET Core:

Фреймворк для разработки веб-приложений и веб-API на .NET Core. Поддерживает разработку высокопроизводительных, масштабируемых и облачно-ориентированных веб-приложений.

🤔 Пример создания простого приложения на .NET Core

Для создания простого консольного приложения на .NET Core можно использовать следующие команды CLI:

1️⃣ Установка .NET Core SDK:

Загрузите и установите .NET Core SDK с официального сайта [Microsoft .NET](https://dotnet.microsoft.com/download).

2️⃣ Создание нового проекта:
   dotnet new console -n MyConsoleApp
cd MyConsoleApp


3️⃣ Редактирование кода:

Откройте файл Program.cs и внесите изменения:
   using System;

namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, .NET Core!");
}
}
}


4️⃣ Запуск приложения:
   dotnet run


🤔 Краткий ответ

.NET Core — это кроссплатформенная, высокопроизводительная и модульная среда выполнения, созданная Microsoft. Она поддерживает Windows, macOS и Linux, позволяет создавать современные приложения и является частью экосистемы .NET.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 Какой модификатор доступа позволяет доступ только внутри того же класса?
Anonymous Quiz
1%
Public
9%
Protected
85%
Private
5%
Internal
👀5
📌 Что такое куча?

💬 Спрашивают в 22% собеседований

В программировании куча (heap) — это область памяти, которая используется для динамического распределения памяти. В отличие от стека, где память выделяется и освобождается автоматически при вызове и завершении функций, куча позволяет разработчику вручную контролировать выделение и освобождение памяти. В контексте C# и .NET, куча имеет свои особенности, связанные с управлением памятью и сборкой мусора (Garbage Collection).

🤔 Основные характеристики кучи

1️⃣ Динамическое распределение памяти:

Куча используется для хранения объектов, которые создаются в процессе выполнения программы с помощью оператора new.

Память в куче выделяется и освобождается динамически, в отличие от статически выделенной памяти на стеке.

2️⃣ Управление памятью:

Память, выделенная в куче, не освобождается автоматически при выходе из функции или блока кода. Разработчик должен явно освобождать её, если это необходимо (в языках с ручным управлением памятью, таких как C и C++).

В C# и .NET, освобождение памяти в куче осуществляется автоматически с помощью сборщика мусора.

3️⃣ Сборка мусора (Garbage Collection):

В .NET среде управляемая куча используется для хранения объектов, и память управляется сборщиком мусора.

Сборщик мусора автоматически освобождает память, занимаемую объектами, которые больше не используются приложением.

🤔 Пример использования кучи в C#

Когда вы создаете новый объект в C#, он размещается в управляемой куче. Рассмотрим простой пример:
class Program
{
static void Main()
{
Person person = new Person();
person.Name = "John";
Console.WriteLine(person.Name);
}
}

class Person
{
public string Name { get; set; }
}


В этом примере:

1️⃣ Person person = new Person(); — создается новый объект типа Person, и память для этого объекта выделяется в куче.

2️⃣ Сборщик мусора автоматически освобождает память, занимаемую объектом Person, когда он больше не нужен (например, после завершения метода Main).

🤔 Сравнение с стеком

1️⃣ Стек (Stack):

Память выделяется автоматически при вызове функции и освобождается при выходе из неё.

Используется для хранения значимых типов (например, int, float, структуры) и указателей на объекты.

Быстрое выделение и освобождение памяти, но ограниченное пространство.

2️⃣ Куча (Heap):

Память выделяется и освобождается динамически.

Используется для хранения объектов и ссылочных типов (например, классов).

Более гибкое управление памятью, но медленное выделение и освобождение по сравнению со стеком.

🤔 Преимущества и недостатки кучи

Преимущества:

Гибкость в управлении памятью, позволяет создавать объекты, срок жизни которых выходит за пределы текущего блока кода или функции.

Подходит для хранения больших объёмов данных и объектов, размер которых неизвестен во время компиляции.

Недостатки:

Более медленное выделение и освобождение памяти по сравнению со стеком.

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

Фрагментация памяти, которая может возникнуть из-за частого выделения и освобождения различных объектов.

🤔 Краткий ответ

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Какая из концепций ООП описывает способность метода работать с объектами разных типов?
Anonymous Quiz
6%
Наследование
72%
Полиморфизм
4%
Инкапсуляция
19%
Абстракция
📌 Где мы используем интерфейсы?

💬 Спрашивают в 22% собеседований

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

🤔 Основные случаи использования интерфейсов

1️⃣ Определение контрактов:

Интерфейсы определяют набор методов и свойств, которые классы должны реализовать, обеспечивая консистентность.

Пример:
     public interface ILogger
{
void Log(string message);
}

public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}


2️⃣ Поддержка полиморфизма:

Интерфейсы позволяют обрабатывать объекты разных классов одинаково, если они реализуют один и тот же интерфейс.

Пример:
     public interface IShape
{
double Area();
}

public class Circle : IShape
{
public double Radius { get; set; }
public double Area() => Math.PI * Radius * Radius;
}

public class Square : IShape
{
public double Side { get; set; }
public double Area() => Side * Side;
}


3️⃣ Ослабление связей (Decoupling):

Интерфейсы помогают ослабить связи между компонентами, делая систему более модульной и легко модифицируемой.

Пример:
     public interface IDataAccess
{
void SaveData(string data);
}

public class DatabaseAccess : IDataAccess
{
public void SaveData(string data)
{
// Сохранение данных в базу данных
}
}

public class FileAccess : IDataAccess
{
public void SaveData(string data)
{
// Сохранение данных в файл
}
}

public class DataService
{
private readonly IDataAccess _dataAccess;

public DataService(IDataAccess dataAccess)
{
_dataAccess = dataAccess;
}

public void Save(string data)
{
_dataAccess.SaveData(data);
}
}


4️⃣ Поддержка множественного наследования:

Классы могут реализовывать несколько интерфейсов, что позволяет реализовать множественное наследование поведения.

Пример:
     public interface IFlyable
{
void Fly();
}

public interface IWalkable
{
void Walk();
}

public class Bird : IFlyable, IWalkable
{
public void Fly()
{
// Логика полета
}

public void Walk()
{
// Логика ходьбы
}
}


5️⃣ Инъекция зависимостей (Dependency Injection):

Интерфейсы часто используются в паттерне инъекции зависимостей для внедрения зависимостей и улучшения тестируемости кода.

Пример:
     public interface IEmailService
{
void SendEmail(string to, string subject, string body);
}

public class EmailService : IEmailService
{
public void SendEmail(string to, string subject, string body)
{
// Логика отправки email
}
}

public class Notification
{
private readonly IEmailService _emailService;

public Notification(IEmailService emailService)
{
_emailService = emailService;
}

public void NotifyUser(string userEmail)
{
_emailService.SendEmail(userEmail, "Notification", "You have a new notification.");
}
}


🤔 Краткий ответ

Интерфейсы используются для определения контрактов, поддержки полиморфизма, ослабления связей между компонентами, реализации множественного наследования, инъекции зависимостей и упрощения тестирования. Они помогают создать гибкую и поддерживаемую архитектуру приложений.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍52🤯1