C# | Вопросы собесов
5.1K subscribers
35 photos
1 file
983 links
Download Telegram
🤔 Может ли быть несколько блоков catch?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
🤔 Что должен возвращать Get hashcode?

Должен возвращать целое число (int), которое представляет хеш-код объекта. Этот хеш-код используется структурами данных, такими как хеш-таблицы (например, Dictionary<TKey, TValue>, HashSet<T>), для быстрого поиска, вставки и удаления объектов.

🚩Основные требования к реализации `GetHashCode`

🟠Согласованность с `Equals`
Если два объекта равны (по методу Equals), то их хеш-коды должны быть одинаковыми. Если Equals возвращает true для двух объектов, их GetHashCode должны возвращать одинаковые значения.

🟠Постоянство
Метод GetHashCode должен возвращать одно и то же значение для одного и того же объекта в пределах одного запуска приложения, при условии, что состояние объекта не изменяется.

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

🚩Примеры реализации `GetHashCode`

Простой пример для одного поля
public class Person
{
public string Name { get; set; }

public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;

Person other = (Person)obj;
return Name == other.Name;
}

public override int GetHashCode()
{
return Name == null ? 0 : Name.GetHashCode();
}
}


Пример для нескольких полей
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }

public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;

Person other = (Person)obj;
return FirstName == other.FirstName && LastName == other.LastName && Age == other.Age;
}

public override int GetHashCode()
{
unchecked // Помогает избежать исключений при переполнении
{
int hash = 17;
hash = hash * 23 + (FirstName == null ? 0 : FirstName.GetHashCode());
hash = hash * 23 + (LastName == null ? 0 : LastName.GetHashCode());
hash = hash * 23 + Age.GetHashCode();
return hash;
}
}
}


Использование HashCode.Combine (начиная с .NET Core 2.1)
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }

public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;

Person other = (Person)obj;
return FirstName == other.FirstName && LastName == other.LastName && Age == other.Age;
}

public override int GetHashCode()
{
return HashCode.Combine(FirstName, LastName, Age);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42
🤔 Для чего нужны нереляционные базы данных?

Нереляционные базы данных (NoSQL) используются для работы с большими объёмами данных, структурированных или неструктурированных, а также для обеспечения гибкости и масштабируемости. Они подходят для хранения документов, ключей-значений, графов или временных рядов. Такие базы, как MongoDB или Redis, идеальны для приложений с динамической структурой данных или высокой нагрузкой.

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

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

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

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

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

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

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

🚩Large Object Heap (LOH)

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

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

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

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

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

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

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

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


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10👾1
🤔 В чем разница между асинхронностью и многопоточностью?

Асинхронность и многопоточность — это два подхода к параллельной обработке задач. Асинхронность позволяет программе продолжать выполнение работы, в то время как она ждет завершения другой задачи (например, ввода/вывода), не блокируя основной поток. Многопоточность включает использование нескольких потоков для выполнения различных задач одновременно, что может ускорить выполнение программы за счет одновременной обработки данных.

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

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

🚩Управляемая куча (Managed Heap)

Это основная область памяти, используемая средой выполнения .NET для управления динамически выделенной памятью. Она разделена на поколения для оптимизации производительности сборки мусора.
🟠Generation 0 (Gen 0)
Содержит новосозданные объекты. Сборка мусора в этом поколении происходит чаще всего. Маленький размер, рассчитанный на быстрое освобождение памяти от краткоживущих объектов.

🟠Generation 1 (Gen 1)
Промежуточное поколение. Объекты, которые пережили сборку мусора в Generation 0, перемещаются в Generation 1. Средний размер, служит буфером между краткоживущими и долгоживущими объектами.

🟠Generation 2 (Gen 2)
Содержит объекты с длительным временем жизни. Объекты, которые пережили сборку мусора в Generation 1, перемещаются в Generation 2. Сборка мусора в этом поколении происходит реже всего. Самый большой размер среди всех поколений.

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

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

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


🚩Куча больших объектов (Large Object Heap, LOH)

Куча больших объектов используется для размещения крупных объектов (размером 85,000 байт и более). LOH имеет свои особенности:

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

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

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

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


🚩Сегментированные кучи (Segmented Heaps)

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

🟠Многопоточность
Позволяет более эффективно использовать многопроцессорные системы.
🟠Изоляция
Каждое ядро работает со своим сегментом памяти, что уменьшает конкуренцию за доступ к памяти.

🚩Упрощенная куча (Ephemeral Heap)

Упрощенная куча представляет собой комбинацию Generation 0 и Generation 1 и используется для оптимизации управления краткоживущими объектами. Этот термин чаще встречается в контексте описания поведения сборщика мусора.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 В чем разница между процессами и потоками?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍1
🤔 Для чего нужно разделение Large object heap и small object heap?

Разделение предназначено для оптимизации управления памятью и производительности работы приложения.

🚩Основные причины

🟠Оптимизация производительности сборщика мусора (GC)
Малые объекты (SOH): Малые объекты имеют более короткий жизненный цикл и размещаются в поколениях (Gen 0, Gen 1 и Gen 2). Сборка мусора для этих объектов происходит чаще и быстрее.
Большие объекты (LOH): Большие объекты имеют тенденцию жить дольше, и сборка мусора для них происходит реже, вместе с Generation 2. LOH не перемещает объекты в памяти, что уменьшает фрагментацию.

🟠Уменьшение фрагментации памяти
SOH: Частые сборки мусора и перемещение объектов в памяти могут вызвать фрагментацию. Однако малые объекты легче перемещать и собирать.
LOH: Большие объекты не перемещаются сборщиком мусора, что уменьшает фрагментацию, но может привести к тому, что большие блоки памяти не будут эффективно использоваться.

🟠Различные стратегии аллокации
SOH: Использует компактные аллокаторы, что обеспечивает эффективное использование памяти для малых объектов и минимизирует накладные расходы.
LOH: Большие объекты требуют более значительных блоков памяти, и их аллокация и деаллокация управляются отдельно для оптимизации использования этих больших блоков.

🚩Плюсы

Эффективное управление памятью
Разделение позволяет лучше управлять памятью для малых и больших объектов, минимизируя накладные расходы и улучшая производительность.
Уменьшение фрагментации
Фрагментация памяти уменьшается, так как большие объекты не перемещаются в памяти, а малые объекты легче компактируются.
Повышение производительности GC
Сборка мусора для малых объектов происходит быстро и часто, тогда как сборка для больших объектов — реже и более эффективно.

🚩Пример использования

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

// Принудительная сборка мусора для малых объектов
GC.Collect(0); // Сборка мусора для Generation 0
}
}


Размещение больших объектов (LOH)
public class Program
{
public static void Main()
{
// Создание большого объекта в LOH
byte[] largeArray = new byte[100000]; // Размер больше 85,000 байт

// Принудительная сборка мусора
GC.Collect(2); // Сборка мусора для Generation 2 и LOH
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 В чем разница между процессами и потоками?

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

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

Lock (монитор), Mutex и Semaphore – это три механизма синхронизации, используемые для управления доступом к общим ресурсам в многопоточном программировании. Хотя все они служат для синхронизации потоков, их поведение и случаи использования различаются.

🟠`Lock` (Монитор)
Lock (в C# используется ключевое слово lock) или Monitor – это механизм синхронизации, который позволяет одному потоку захватить блокировку для определенной области кода, чтобы другие потоки не могли войти в эту область кода до освобождения блокировки.
Область действия: Только внутри одного процесса.
Рекурсивность: Поддерживает рекурсивные блокировки (один и тот же поток может захватить блокировку несколько раз).
Простота использования: Легко использовать с ключевым словом lock.
private readonly object _lockObject = new object();

public void CriticalSection()
{
lock (_lockObject)
{
// Критическая секция
}
}


🟠`Mutex`
Mutex (Mutual Exclusion) – это более сложный механизм синхронизации, который может использоваться для синхронизации потоков как внутри одного процесса, так и между разными процессами.
Область действия: Может использоваться как внутри одного процесса, так и между разными процессами.
Рекурсивность: Не поддерживает рекурсивные блокировки по умолчанию.
Использование: Требует явного захвата и освобождения блокировки.
private readonly Mutex _mutex = new Mutex();

public void CriticalSection()
{
_mutex.WaitOne(); // Захват мьютекса
try
{
// Критическая секция
}
finally
{
_mutex.ReleaseMutex(); // Освобождение мьютекса
}
}


🟠`Semaphore`
Semaphore – это механизм синхронизации, который ограничивает доступ к ресурсу заданным количеством потоков одновременно. Существует два типа семафоров: Semaphore и SemaphoreSlim.
Область действия: Может использоваться для синхронизации потоков внутри одного процесса (SemaphoreSlim) и между разными процессами (Semaphore).
Многократный доступ: Позволяет нескольким потокам одновременно получать доступ к ресурсу, если количество разрешений больше нуля.
Использование: Требует явного захвата и освобождения разрешения.
private readonly Semaphore _semaphore = new Semaphore(3, 3); // Максимум 3 потока

public void CriticalSection()
{
_semaphore.WaitOne(); // Захват семафора
try
{
// Критическая секция
}
finally
{
_semaphore.Release(); // Освобождение семафора
}
}


🚩Ключевые различия

🟠Область действия
Lock: Только внутри одного процесса.
Mutex: Может использоваться для синхронизации между процессами.
Semaphore: Может использоваться для синхронизации между процессами (Semaphore) и внутри одного процесса (SemaphoreSlim).

🟠Рекурсивность
Lock: Поддерживает рекурсивные блокировки.
Mutex: Не поддерживает рекурсивные блокировки по умолчанию.
Semaphore: Не поддерживает рекурсивные блокировки.

🟠Многократный доступ
Lock: Только один поток может захватить блокировку.
Mutex: Только один поток может захватить блокировку.
Semaphore: Несколько потоков могут захватить блокировку одновременно, если разрешений больше нуля.

🟠Простота использования
Lock: Легко использовать с ключевым словом lock.
Mutex: Требует явного захвата и освобождения блокировки.
Semaphore: Требует явного захвата и освобождения разрешений.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍63
🤔 Для чего нужны нереляционные базы данных?

Нереляционные базы данных (NoSQL) используются для работы с большими объёмами данных, структурированных или неструктурированных, а также для обеспечения гибкости и масштабируемости. Они подходят для хранения документов, ключей-значений, графов или временных рядов. Такие базы, как MongoDB или Redis, идеальны для приложений с динамической структурой данных или высокой нагрузкой.

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

Это делегат, представляющий метод, который принимает один или несколько аргументов и возвращает логическое значение (true или false). Предикаты часто используются для фильтрации коллекций, поиска элементов и других операций, связанных с условными проверками.

🚩Особенности

🟠Тип делегата
В C# предикат представлен делегатом Predicate<T>, который принимает один аргумент типа T и возвращает bool.

🟠Использование
Предикаты обычно используются в методах стандартных коллекций, таких как List<T>, для поиска, удаления и фильтрации элементов.

🚩Пример использования предиката

Определение предиката
public static bool IsEven(int number)
{
return number % 2 == 0;
}


Использование предиката с методом коллекции
using System;
using System.Collections.Generic;

public class Program
{
public static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

// Использование предиката для поиска первого четного числа
int firstEven = numbers.Find(IsEven);
Console.WriteLine("First even number: " + firstEven);

// Использование предиката для удаления всех четных чисел
numbers.RemoveAll(IsEven);
Console.WriteLine("Numbers after removing evens: " + string.Join(", ", numbers));
}

public static bool IsEven(int number)
{
return number % 2 == 0;
}
}


🚩Лямбда-выражения как предикаты

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

Пример использования лямбда-выражений
using System;
using System.Collections.Generic;

public class Program
{
public static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

// Использование лямбда-выражения для поиска первого четного числа
int firstEven = numbers.Find(n => n % 2 == 0);
Console.WriteLine("First even number: " + firstEven);

// Использование лямбда-выражения для удаления всех четных чисел
numbers.RemoveAll(n => n % 2 == 0);
Console.WriteLine("Numbers after removing evens: " + string.Join(", ", numbers));
}
}


🚩Сценарии использования предикатов

🟠Фильтрация коллекций
Предикаты используются для определения условий фильтрации элементов в коллекциях.
List<int> evenNumbers = numbers.FindAll(IsEven);   


🟠Поиск элементов
Предикаты помогают находить элементы, соответствующие определенному условию.
int firstEven = numbers.Find(IsEven);   


🟠Удаление элементов
Предикаты используются для удаления элементов, соответствующих определенному условию.
numbers.RemoveAll(IsEven);   


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍1
🤔 Что такое builder паттерн?

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

🚩Основные цели и задачи паттерна

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

🟠Пошаговое создание объектов
Позволяет создавать объекты поэтапно, контролируя процесс конструирования и предотвращая создание объекта в неконсистентном состоянии.

🟠Поддержка неизменяемых объектов
Может использоваться для создания неизменяемых объектов с большим количеством опций и параметров.

🚩Структура паттерна

🟠Builder
Определяет интерфейс для пошагового конструирования объекта.
🟠ConcreteBuilder
Реализует интерфейс Builder и создает конкретный продукт.
🟠Director
Управляет объектом Builder и задает алгоритм создания объекта.
🟠Product
Класс, представляющий создаваемый сложный объект.

🚩Пример использования паттерна Строитель

1⃣Определение продукта
public class House
{
public string Walls { get; set; }
public string Roof { get; set; }
public string Foundation { get; set; }

public override string ToString()
{
return $"House with {Walls}, {Roof} and {Foundation}";
}
}


2⃣Определение интерфейса Builder
public interface IHouseBuilder
{
void BuildFoundation();
void BuildWalls();
void BuildRoof();
House GetHouse();
}


3⃣Реализация конкретного Builder
public class ConcreteHouseBuilder : IHouseBuilder
{
private House _house = new House();

public void BuildFoundation()
{
_house.Foundation = "Concrete Foundation";
}

public void BuildWalls()
{
_house.Walls = "Concrete Walls";
}

public void BuildRoof()
{
_house.Roof = "Concrete Roof";
}

public House GetHouse()
{
return _house;
}
}


4⃣Определение Director
public class ConstructionDirector
{
private readonly IHouseBuilder _builder;

public ConstructionDirector(IHouseBuilder builder)
{
_builder = builder;
}

public void ConstructHouse()
{
_builder.BuildFoundation();
_builder.BuildWalls();
_builder.BuildRoof();
}
}


5⃣Использование паттерна Строитель
public class Program
{
public static void Main()
{
IHouseBuilder builder = new ConcreteHouseBuilder();
ConstructionDirector director = new ConstructionDirector(builder);

director.ConstructHouse();
House house = builder.GetHouse();

Console.WriteLine(house); // Output: House with Concrete Walls, Concrete Roof and Concrete Foundation
}
}


🚩Плюсы

Контроль процесса создания
Позволяет контролировать процесс создания сложных объектов поэтапно.
Гибкость
Разделение конструирования и представления позволяет использовать один и тот же процесс для создания различных объектов.
Читаемость кода
Код становится более читаемым и поддерживаемым, так как процесс создания объекта инкапсулирован в отдельный класс.
Поддержка сложных объектов
Упрощает создание объектов с множеством параметров и сложной иерархией.

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

Lock-еры — это объекты или механизмы, такие как lock в C#, которые предотвращают одновременный доступ к критическим участкам кода из нескольких потоков. Они обеспечивают безопасное выполнение кода в многопоточной среде, исключая гонки данных. Например, lock блокирует выполнение других потоков, пока текущий поток не завершит работу с ресурсом.

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

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

🚩IEnumerable

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

🟠Методы расширения LINQ
Методы LINQ, такие как Where, Select и другие, применяются к объекту IEnumerable и выполняются на стороне клиента. Каждый метод LINQ создает новую коллекцию, что может привести к повышенным затратам памяти и времени выполнения.

🟠Ленивая загрузка (Lazy Loading)
Операции с IEnumerable выполняются лениво, т.е. элементы коллекции обрабатываются по мере их запроса.

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

// Пример запроса LINQ с использованием IEnumerable
IEnumerable<int> evenNumbers = numbers.Where(n => n % 2 == 0);

foreach (int number in evenNumbers)
{
Console.WriteLine(number); // Выведет 2 и 4
}


🚩IQueryable

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

🟠Построение выражений
IQueryable поддерживает построение и выполнение выражений LINQ, которые могут быть оптимизированы источником данных перед выполнением.

🟠Отложенное выполнение (Deferred Execution)
Запросы IQueryable не выполняются сразу при их определении. Они выполняются только при итерации или вызове метода, который требует выполнения запроса (например, ToList, FirstOrDefault).

using System.Linq;
using System.Data.Entity; // Пример для Entity Framework

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

public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}

public class Program
{
public static void Main()
{
using (var context = new MyDbContext())
{
// Пример запроса LINQ с использованием IQueryable
IQueryable<Product> expensiveProducts = context.Products.Where(p => p.Price > 100);

foreach (Product product in expensiveProducts)
{
Console.WriteLine(product.Name);
}
}
}
}


🚩Как понять, что использовать

🟠Используйте `IEnumerable`, если
Коллекция уже загружена в память. Вы работаете с небольшими наборами данных. Не требуется выполнение запросов на стороне сервера.
🟠Используйте `IQueryable`, если
Вы выполняете запросы к базе данных или другому удаленному источнику данных. Требуется отложенное выполнение запросов для оптимизации выполнения. Нужно минимизировать объем данных, загружаемых в память, путем фильтрации на стороне сервера.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
🤔 Как работает сборка мусора на платформе .NET?

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

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

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

🟠Определение возвращаемого типа метода
Когда вы объявляете метод, вы явно указываете его возвращаемый тип. Компилятор использует эту информацию, чтобы проверить, что метод действительно возвращает значение этого типа во всех возможных путях выполнения.
public int Add(int a, int b)
{
return a + b; // Компилятор проверяет, что возвращаемое значение соответствует типу int
}


Пример
public void PrintMessage(string message)
{
Console.WriteLine(message); // Метод ничего не возвращает
}


🟠Определение типа выражений
Компилятор также использует систему типов для определения возвращаемого значения выражений. Операторы, такие как +, -, *, и =, имеют определенные правила типов.
int x = 5;
int y = 10;
int result = x + y; // Компилятор знает, что результат x + y будет int


🟠Лямбда-выражения и делегаты
При использовании лямбда-выражений и делегатов компилятор также проверяет соответствие типов.
Func<int, int, int> add = (a, b) => a + b;
int result = add(3, 4); // Компилятор знает, что add возвращает int


🟠Использование `return`
Компилятор проверяет все пути выполнения метода, чтобы убедиться, что в конце каждого пути выполняется return, если метод должен возвращать значение.
public int Max(int a, int b)
{
if (a > b)
{
return a;
}
else
{
return b;
}
}


Если метод может не вернуть значение в каком-то пути выполнения, компилятор выдаст ошибку.
public int Max(int a, int b)
{
if (a > b)
{
return a;
}
// Ошибка компиляции: не все пути возвращают значение
}


🟠Полиморфизм и переопределение методов
Когда вы используете полиморфизм и переопределение методов, компилятор также использует информацию о типах, чтобы определить, какой метод будет вызван.
public class Animal
{
public virtual string Speak()
{
return "Some sound";
}
}

public class Dog : Animal
{
public override string Speak()
{
return "Bark";
}
}

Animal myDog = new Dog();
string sound = myDog.Speak(); // Компилятор знает, что Speak вернет string, и вызовется метод из Dog


🟠Использование асинхронных методов
Для асинхронных методов с возвращаемым типом Task или Task<T>, компилятор проверяет, что метод возвращает соответствующий тип.
public async Task<int> GetNumberAsync()
{
await Task.Delay(1000);
return 42; // Компилятор проверяет, что возвращаемое значение соответствует Task<int>
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 В чем отличие Dispose и Finalize?

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

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

Индексы в базах данных, таких как SQL Server, MySQL или PostgreSQL, существенно улучшают производительность запросов, особенно для операций поиска, сортировки и фильтрации. Однако у индексов есть и минусы, которые могут негативно сказаться на производительности и других аспектах работы базы данных.

🟠Увеличение времени записи
Индексы замедляют операции вставки (INSERT), обновления (UPDATE) и удаления (DELETE), так как при каждом изменении данных необходимо также обновлять индексы.
Вставка: При вставке новой записи нужно обновить все соответствующие индексы.
Обновление: При обновлении записи могут изменяться индексируемые колонки, что требует обновления индексов.
Удаление: При удалении записи нужно удалить соответствующие записи из индексов.

🟠Дополнительное использование памяти и дискового пространства
Индексы занимают дополнительное пространство на диске и в оперативной памяти. Чем больше индексов на таблице, тем больше требуется места для их хранения.
Дисковое пространство: Каждому индексу требуется место на диске для хранения его данных.
Память: Индексы занимают память при их использовании, особенно в случае часто запрашиваемых индексов, которые кэшируются в оперативной памяти.

🟠Замедление операций массовой загрузки данных
При массовой загрузке данных, например, при использовании операций LOAD DATA или BULK INSERT, наличие индексов замедляет процесс, так как индексы должны обновляться по мере добавления каждой записи.

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

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

🟠Перекрестные индексы
Наличие нескольких индексов на одной таблице может привести к конфликтам при планировании запросов. Оптимизатор запросов может выбирать менее эффективные индексы, что ухудшает производительность.

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

🚩Пример ситуации

CREATE TABLE Employees (
EmployeeID INT PRIMARY KEY,
FirstName VARCHAR(50),
LastName VARCHAR(50),
DepartmentID INT,
Salary DECIMAL(10, 2)
);

CREATE INDEX idx_firstname ON Employees(FirstName);
CREATE INDEX idx_lastname ON Employees(LastName);
CREATE INDEX idx_department ON Employees(DepartmentID);


🚩Минусы

Вставка данных
INSERT INTO Employees (EmployeeID, FirstName, LastName, DepartmentID, Salary)
VALUES (1, 'John', 'Doe', 10, 60000.00);


Обновление данных
UPDATE Employees
SET Salary = Salary * 1.05
WHERE DepartmentID = 10;


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Какие механизмы позволяют не нарушать принцип dependency inversion?

Для соблюдения принципа dependency inversion используются интерфейсы и абстракции, которые позволяют код зависеть от общего поведения, а не от конкретных реализаций. Также помогают фабрики (Factories) для создания объектов и DI-контейнеры (Dependency Injection), которые управляют зависимостями и их внедрением.

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

Это структура данных, используемая в системах управления базами данных (СУБД) для организации и ускорения доступа к данным. B-tree индекс является сбалансированным деревом, обеспечивающим эффективное выполнение операций поиска, вставки, удаления и диапазонного поиска. B-tree индекс используется большинством реляционных СУБД, таких как SQL Server, MySQL, PostgreSQL и Oracle.

🚩Основные характеристики B-tree индекса

🟠Сбалансированное дерево
B-tree индекс является сбалансированным деревом, где все листья находятся на одном уровне. Это обеспечивает равномерное время доступа к данным.

🟠Ключи и значения
В узлах B-tree хранятся ключи, которые могут ссылаться на строки в таблице или на другие узлы дерева.

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

🟠Диапазонные запросы
B-tree индекс эффективно поддерживает диапазонные запросы (например, поиск всех записей с ключами между заданными значениями).

🟠Динамическое поддержание
B-tree автоматически сбалансирован, что позволяет эффективно выполнять операции вставки, удаления и обновления.

🚩Пример использования

CREATE TABLE Employees (
EmployeeID INT PRIMARY KEY,
FirstName VARCHAR(50),
LastName VARCHAR(50),
DepartmentID INT,
Salary DECIMAL(10, 2)
);

CREATE INDEX idx_lastname ON Employees(LastName);


🚩Операции

🟠Поиск
Операция поиска в B-tree выполняется за логарифмическое время O(log n), где n — количество узлов.
SELECT * FROM Employees WHERE LastName = 'Smith';   


🟠Диапазонный поиск
Диапазонные запросы, такие как поиск всех сотрудников с фамилией от 'A' до 'M', выполняются эффективно.
SELECT * FROM Employees WHERE LastName BETWEEN 'A' AND 'M';   


🟠Вставка
При вставке новой записи в таблицу с индексом B-tree, запись добавляется в соответствующее место, поддерживая балансировку дерева.
INSERT INTO Employees (EmployeeID, FirstName, LastName, DepartmentID, Salary)
VALUES (1, 'John', 'Doe', 10, 60000.00);


🟠Удаление
При удалении записи соответствующий ключ удаляется из B-tree, и дерево автоматически перестраивается, чтобы сохранить балансировку.
DELETE FROM Employees WHERE EmployeeID = 1;   


🚩Плюсы

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

🚩Минусы

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

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1