Вот классификация:
Идемпотентные:
- GET — многократный вызов не меняет состояние.
- PUT — задаёт конкретное состояние ресурса.
- DELETE — может быть вызван многократно с тем же результатом.
- HEAD, OPTIONS — тоже идемпотентны.
Неидемпотентные:
- POST — каждый вызов может создавать новый ресурс или изменять состояние (непредсказуемо).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Делегаты — это типы, которые безопасно инкапсулируют методы, подобно указателям на функции в других языках программирования, но с проверкой типов во время компиляции. Могут ссылаться на метод, который принимает параметры и возвращает значение. Они используются для реализации обратных вызовов и событий, а также для определения пользовательских операций, которые могут быть выполнены методом, принимаемым в качестве параметра.
Делегаты предоставляют механизм для передачи методов в качестве аргументов другим методам. Это полезно для реализации обратных вызовов, позволяя вызывать методы в ответ на определенные события или условия.
Являются основой системы событий. Они позволяют определять события и подписываться на них. Когда событие происходит, вызываются делегаты, связанные с этим событием, что позволяет реагировать на изменения или действия пользователя.
Позволяют создавать более гибкие и масштабируемые приложения, поскольку методы могут быть переданы и использованы динамически в различных контекстах.
Используются для асинхронного программирования, позволяя выполнять задачи в фоновом режиме, не блокируя основной поток приложения.
public delegate int Operation(int x, int y);
public class Calculator
{
public int PerformOperation(int x, int y, Operation op)
{
return op(x, y);
}
}
class Program
{
static int Add(int x, int y)
{
return x + y;
}
static int Multiply(int x, int y)
{
return x * y;
}
static void Main()
{
Calculator calc = new Calculator();
// Создание делегата для метода Add и вызов через метод PerformOperation
Operation addOp = new Operation(Add);
int result = calc.PerformOperation(5, 6, addOp);
Console.WriteLine("Addition: " + result);
// Создание делегата для метода Multiply и вызов через метод PerformOperation
Operation mulOp = new Operation(Multiply);
result = calc.PerformOperation(5, 6, mulOp);
Console.WriteLine("Multiplication: " + result);
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это автоматический процесс управления памятью, который освобождает память, занятую объектами, которые больше не используются приложением. Этот механизм помогает разработчикам избежать ошибок, связанных с управлением памятью вручную, таких как утечки памяти и неправильное использование освобожденных ресурсов.
Управляемая куча — это область памяти, в которой размещаются объекты, созданные в управляемой среде .NET. Когда создается новый объект, память для него выделяется в управляемой куче.
Корни — это переменные и ссылки, которые являются начальными точками для сборки мусора. Они включают глобальные и статические переменные, локальные переменные в стеке, а также ссылки из регистров процессора.
GC использует алгоритм маркировки и сжатия для определения объектов, которые больше не используются. Сначала он помечает все доступные объекты (те, до которых можно добраться из корней), а затем удаляет все непомеченные объекты, освобождая их память.
Память управляемой кучи разделена на три поколения: поколение 0, поколение 1 и поколение 2. Это позволяет оптимизировать процесс сборки мусора:
Поколение 0: Содержит новые объекты. Сборка мусора здесь происходит чаще всего, так как большинство объектов живут недолго.
Поколение 1: Содержит объекты, которые пережили одну сборку мусора.
Поколение 2: Содержит объекты, которые пережили несколько сборок мусора. Сборка мусора здесь происходит реже всего, так как такие объекты считаются долгоживущими.
Когда выделяется новая память и управляемая куча достигает определенного порога, запускается процесс сборки мусора.
GC проходит по всем корням и помечает все объекты, которые могут быть достигнуты.
После маркировки все непомеченные объекты считаются недоступными и могут быть удалены.
Для улучшения производительности и уменьшения фрагментации памяти, сборщик мусора может переместить оставшиеся объекты, чтобы освободить блоки памяти.
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
{
// Поля и методы класса
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
- Используйте, когда требуется задать общий контракт для классов без предоставления реализации.
- Подходит для ситуаций, где объекты могут принадлежать разным иерархиям.
2. Абстрактный класс:
- Используйте, когда нужно предоставить частичную реализацию вместе с контрактом.
- Подходит для классов в одной иерархии, где есть общая логика.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
В современном C# паттерн Singleton можно реализовать несколькими способами, каждый из которых имеет свои преимущества и предназначен для различных сценариев использования. Рассмотрим несколько распространенных подходов к реализации Singleton.
Ленивый Singleton инициализируется при первом обращении. Это обеспечивает отложенную инициализацию объекта и гарантирует потокобезопасность.
public class Singleton
{
private static readonly Lazy<Singleton> lazyInstance = new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance => lazyInstance.Value;
private Singleton()
{
// Приватный конструктор
}
}
Этот подход использует
lock для обеспечения потокобезопасности при создании экземпляра.public class Singleton
{
private static Singleton instance;
private static readonly object lockObj = new object();
private Singleton()
{
// Приватный конструктор
}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (lockObj)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
Eager Initialization (Инициализация при загрузке)
Экземпляр Singleton создается при загрузке класса. Это гарантирует потокобезопасность за счет особенностей инициализации статических переменных в .NET.
public class Singleton
{
private static readonly Singleton instance = new Singleton();
public static Singleton Instance => instance;
private Singleton()
{
// Приватный конструктор
}
}
Использование статического конструктора для инициализации Singleton.
public class Singleton
{
private static readonly Singleton instance;
static Singleton()
{
instance = new Singleton();
}
public static Singleton Instance => instance;
private Singleton()
{
// Приватный конструктор
}
}
Singleton с внедрением зависимостей (Dependency Injection)
В современных приложениях, особенно с использованием ASP.NET Core, Singleton часто регистрируется в контейнере внедрения зависимостей.
public class SingletonService
{
public void DoWork()
{
// Выполнение работы
}
}
// Регистрация в контейнере служб
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<SingletonService>();
}
// Использование в контроллере
public class MyController : ControllerBase
{
private readonly SingletonService _singletonService;
public MyController(SingletonService singletonService)
{
_singletonService = singletonService;
}
public IActionResult Index()
{
_singletonService.DoWork();
return Ok();
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
REST (Representational State Transfer) — это архитектурный стиль разработки веб-сервисов, который стал основным методом создания веб-API. Этот стиль был введён Роем Филдингом в его докторской диссертации в 2000 году и основывается на принципах, используемых в протоколе HTTP.
Архитектура строится на разделении клиента и сервера. Это разделение позволяет разрабатывать клиентскую и серверную части независимо друг от друга, что упрощает разработку и тестирование.
Каждый запрос от клиента к серверу должен содержать всю информацию, необходимую серверу для его понимания и выполнения. Сервер не должен хранить информацию о состоянии клиента между запросами. Если это необходимо, состояние следует хранить на клиенте.
Ответы сервера должны быть явно помечены как кэшируемые или некэшируемые, чтобы клиенты могли кэшировать данные и повышать производительность, уменьшая количество запросов к серверу.
Важнейший из принципов REST — единый интерфейс, который упрощает и обобщает взаимодействие между клиентом и сервером. Этот интерфейс определяет стандартные методы и форматы обмена информацией, которые должны быть одинаковыми для всех ресурсов. Типичными методами являются GET, POST, PUT, DELETE.
Клиент не должен предполагать, что он напрямую соединён с сервером. Между ними может находиться несколько слоёв, таких как балансировщики нагрузки или кэширующие прокси.
Серверы могут временно расширять или настраивать функционал на клиентах, передавая им исполняемый код (например, JavaScript).
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1🤔1
Это порождающий паттерн проектирования, который используется для пошагового создания сложных объектов. Он разделяет процесс конструирования объекта от его представления, позволяя создавать различные представления объекта, следуя одному и тому же процессу конструирования.
Отделяет процесс конструирования объекта от его представления, чтобы один и тот же процесс мог использоваться для создания различных представлений объекта.
Позволяет создавать объекты поэтапно, контролируя процесс конструирования и предотвращая создание объекта в неконсистентном состоянии.
Может использоваться для создания неизменяемых объектов с большим количеством опций и параметров.
Определяет интерфейс для пошагового конструирования объекта.
Реализует интерфейс Builder и создает конкретный продукт.
Управляет объектом Builder и задает алгоритм создания объекта.
Класс, представляющий создаваемый сложный объект.
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}";
}
}
public interface IHouseBuilder
{
void BuildFoundation();
void BuildWalls();
void BuildRoof();
House GetHouse();
}
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;
}
}
public class ConstructionDirector
{
private readonly IHouseBuilder _builder;
public ConstructionDirector(IHouseBuilder builder)
{
_builder = builder;
}
public void ConstructHouse()
{
_builder.BuildFoundation();
_builder.BuildWalls();
_builder.BuildRoof();
}
}
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
👍2
Нет. Абстрактный метод может быть объявлен только внутри абстрактного класса.
Если попытаться объявить абстрактный метод в обычном классе, компилятор выдаст ошибку.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥3
Абстрактный класс и интерфейс - это два механизма, которые обеспечивают наследование и полиморфизм, но они используются по-разному и для разных целей.
Представляет собой класс, от которого нельзя создать экземпляр напрямую. Он предназначен для описания общего поведения и состояния своих подклассов. Абстрактные классы могут содержать реализацию некоторых методов и свойств. Это означает, что абстрактный класс может содержать как абстрактные методы (без реализации), так и методы с реализацией. Подклассы абстрактного класса обязаны реализовать все абстрактные методы, но они также наследуют реализованные методы и свойства.
public abstract class Животное
{
public abstract void Есть(); // Абстрактный метод, должен быть реализован в наследнике.
public void Дышать() // Метод с реализацией, наследуется всеми наследниками.
{
Console.WriteLine("Дыхание");
}
}
Интерфейс определяет контракт, который классы или структуры могут реализовывать. Интерфейсы могут содержать объявления методов, свойств, событий, но не их реализации. Класс или структура, реализующие интерфейс, должны предоставить реализацию для всех его членов. Важно отметить, что класс может реализовывать несколько интерфейсов, что обеспечивает форму множественного наследования.
public interface IЖивотное
{
void Есть(); // Метод, который должен быть реализован в классе.
}
Класс может наследовать только от одного абстрактного класса (из-за ограничения одиночного наследования в C#), но может реализовывать множество интерфейсов.
Абстрактные классы могут содержать реализацию методов и поля данных, в то время как интерфейсы могут содержать только объявления методов и свойств (без полей и реализации).
Абстрактные классы могут иметь конструкторы и деструкторы, в то время как интерфейсы - нет.
В интерфейсах все члены по умолчанию являются public, и вы не можете указать другой модификатор доступа. В абстрактных классах вы можете использовать различные модификаторы доступа.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔4👍3🔥1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊4
Оператор
new в C# создаёт новый экземпляр объекта и выделяет для него память в куче (Heap) или стеке (Stack), в зависимости от типа. Для классов (
class) – выделяет память в куче (Heap) и возвращает ссылку на объект. Для структур (
struct) – если структура создаётся без new, её поля остаются неинициализированными, но если использовать new, она получает значения по умолчанию. Для массивов (
T[]) – выделяет память в куче, даже если T – это struct. Для делегатов – создаёт экземпляр делегата.
Пример:
new с классом (class)class Person
{
public string Name;
public Person(string name)
{
Name = name;
}
}
class Program
{
static void Main()
{
Person p1 = new Person("Alice"); // Создаём новый объект в куче
Console.WriteLine(p1.Name); // Alice
}
}
Пример:
new со структурой (struct)struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
}
class Program
{
static void Main()
{
Point p1 = new Point(5, 10); // Создаёт структуру в стеке
Console.WriteLine(p1.X); // 5
}
}
Пример:
new с массивомint[] numbers = new int[5]; // Создаёт массив в куче
numbers[0] = 10;
Console.WriteLine(numbers[0]); // 10
Выделение памяти в куче (для классов) или в стеке (для структур).
Вызов конструктора класса или структуры.
Возвращение ссылки на объект (для классов) или самого объекта (для структур).
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Суть реализации:
- Есть абстрактный интерфейс фабрики, определяющий методы создания продуктов.
- Есть конкретные реализации этой фабрики, каждая из которых возвращает продукты одного "семейства".
- Клиент работает с абстракциями, не зная конкретных реализаций.
Это обеспечивает гибкость, масштабируемость и ослабленную связанность между компонентами.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Исключения в программировании — это механизмы обработки ошибок и необычных ситуаций, которые возникают во время выполнения программы. В C# и других языках программирования исключения позволяют отделить код обработки ошибок от основного кода программы, что упрощает его чтение и поддержку.
Событие, которое прерывает нормальный поток выполнения программы.
Содержит код, который может вызвать исключение.
Содержит код, который выполняется, если возникает исключение. В catch блок можно передать параметр — экземпляр исключения, которое произошло.
Содержит код, который выполняется в любом случае, независимо от того, произошло исключение или нет. Обычно используется для освобождения ресурсов.
Механизм для явного вызова исключения.
Основные блоки
try
{
// Код, который может вызвать исключение
int divisor = 0;
int result = 10 / divisor;
}
catch (DivideByZeroException ex)
{
// Обработка исключения
Console.WriteLine("Деление на ноль невозможно.");
}
finally
{
// Код, который выполнится в любом случае
Console.WriteLine("Блок finally выполнен.");
}
Создание и бросание собственного исключения
public class InvalidAgeException : Exception
{
public InvalidAgeException(string message) : base(message) { }
}
public void SetAge(int age)
{
if (age < 0)
{
throw new InvalidAgeException("Возраст не может быть отрицательным.");
}
// Логика установки возраста
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2💊1
Ты говоришь про объекты в нулевом поколении (Generation 0) в сборщике мусора (Garbage Collector, GC) в .NET? Если да, то это очень хорошая тема!
самые молодые объекты. Это временные, краткоживущие данные, которые часто быстро удаляются.
промежуточное поколение. Объекты, пережившие хотя бы одну очистку Gen 0.
долгоживущие объекты. Обычно это крупные структуры данных, которые редко изменяются.
GC оптимизирован так, что маленькие и "короткоживущие" объекты (например, переменные внутри метода) создаются в Gen 0 и быстро удаляются. Это позволяет экономить память и ускорять работу приложения.
Если объект долго живет, он "повышается" в следующее поколение (Gen 1, затем Gen 2). GC чаще очищает Gen 0, а Gen 2 – реже, так как там хранятся важные данные, которые не стоит часто перемещать.
Очень недолго! Вся идея Gen 0 в том, чтобы быстро выделять и быстро освобождать память. Если объект не используется после первой очистки GC, он удаляется. Если объект нужен дальше – он переходит в Gen 1.
class Program
{
static void Main()
{
for (int i = 0; i < 1000; i++)
{
var obj = new object(); // Создаем объект в Gen 0
} // obj выходит из области видимости и уничтожается GC
}
}
Здесь объекты быстро уничтожаются в Gen 0, так как они больше не нужны.
А если объект нужен долго:
class Program
{
static object _longLivingObject = new object(); // Скорее всего, попадет в Gen 2
static void Main()
{
Console.WriteLine("Объект долго живёт!");
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊8
- Жадная (Eager) загрузка — данные загружаются вместе с основным объектом сразу, обычно через Include. Это снижает количество запросов, но может привести к избытку данных.
- Ленивая (Lazy) загрузка — связанные данные подгружаются только при первом доступе к ним. Это удобно, но требует осторожности (можно случайно вызвать лишние запросы).
- Явная (Explicit) загрузка — данные подгружаются вручную при необходимости, через отдельный вызов. Такой подход даёт полный контроль, но требует больше кода.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Сравнение значений переменных может зависеть от типа данных, хранящихся в этих переменных, и от способа их сравнения.
Для примитивных типов (например,
int, float, char, bool) значение хранятся непосредственно в переменных, и их сравнение выполняется по значению. int a = 5;
int b = 5;
bool areEqual = (a == b); // True
Для ссылочных типов (например, классы, строки) переменные содержат ссылки на объекты в куче. Сравнение ссылочных типов по умолчанию выполняется по ссылке, а не по значению.
class Person
{
public string Name { get; set; }
}
Person person1 = new Person { Name = "Alice" };
Person person2 = new Person { Name = "Alice" };
bool areEqual = (person1 == person2); // False, потому что сравниваются ссылки
Строки являются ссылочными типами, но переопределяют операторы сравнения
== и Equals для сравнения по значению. string str1 = "Hello";
string str2 = "Hello";
bool areEqual = (str1 == str2); // True, строки сравниваются по значению
Для кастомных классов можно переопределить методы
Equals и GetHashCode, чтобы сравнивать объекты по значению. 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.GetHashCode();
}
}
Person person1 = new Person { Name = "Alice" };
Person person2 = new Person { Name = "Alice" };
bool areEqual = person1.Equals(person2); // True
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2