- Отложенное выполнение (deferred execution) — данные не вычисляются до тех пор, пока к ним не обратятся, как в IEnumerable, yield, LINQ.
- Немедленное выполнение (immediate execution) — результат вычисляется сразу при вызове метода (например, ToList(), Count()).
Отложенное выполнение экономит ресурсы, но требует внимательности к источнику данных.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
CancellationToken в C# используется для координации отмены между потоками. Это механизм, позволяющий запрашивать отмену операции (например, задачи Task или асинхронного метода), не прерывая поток принудительно.В многопоточных или асинхронных операциях бывает необходимо отменить выполнение кода, например:
Пользователь отменил загрузку файла.
Истек тайм-аут выполнения операции.
Нужно прервать выполнение нескольких связанных задач.
Источник токена (
CancellationTokenSource) управляет токеном (CancellationToken), который передаётся в задачи.Код регулярно проверяет
cancellationToken.IsCancellationRequested, чтобы определить, нужно ли остановиться.Если вызывается
cts.Cancel(), все методы, использующие этот токен, получают сигнал об отмене.using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var cts = new CancellationTokenSource();
// Отменяем операцию через 3 секунды
cts.CancelAfter(3000);
try
{
await DoWorkAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Операция отменена!");
}
}
static async Task DoWorkAsync(CancellationToken cancellationToken)
{
for (int i = 0; i < 10; i++)
{
cancellationToken.ThrowIfCancellationRequested(); // Проверка отмены
Console.WriteLine($"Работаем... {i}");
await Task.Delay(1000, cancellationToken); // Ожидание с проверкой отмены
}
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1🤔1
Extension-методы (методы расширения) — это способ добавить новые методы к существующим классам, не изменяя их код и не создавая наследников. Они позволяют расширять классы и интерфейсы, даже если у нас нет доступа к их исходному коду.
Это обычные статические методы, но объявленные внутри статического класса.
Первый параметр метода должен принимать тот тип, который мы хотим расширить, и перед ним ставится ключевое слово
this. После этого метод становится доступен как "встроенный" у этого типа.
Допустим, у нас есть строка, и мы хотим добавить метод
ToSnakeCase, который заменяет пробелы на нижние подчеркивания. using System;
public static class StringExtensions
{
public static string ToSnakeCase(this string str)
{
return str.Replace(" ", "_").ToLower();
}
}
class Program
{
static void Main()
{
string text = "Hello World";
Console.WriteLine(text.ToSnakeCase()); // hello_world
}
}
Добавим метод `SumEvenNumbers()`, который суммирует только четные числа в
List<int>. using System;
using System.Collections.Generic;
using System.Linq;
public static class ListExtensions
{
public static int SumEvenNumbers(this List<int> numbers)
{
return numbers.Where(n => n % 2 == 0).Sum();
}
}
class Program
{
static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(numbers.SumEvenNumbers()); // 12 (2 + 4 + 6)
}
}
Когда нужно добавить новый метод к существующему классу, но нельзя изменить его код (например,
string, List<T>, DateTime). Когда хочется сделать код более читаемым:
numbers.SumEvenNumbers() лучше, чем MyExtensions.SumEvenNumbers(numbers). Когда нужно улучшить API без наследования и изменения структуры классов.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6💊1
Singleton — это жизненный цикл зависимости, при котором:
- Экземпляр создаётся один раз за всё время жизни приложения.
- Все зависимости получают один и тот же объект.
Хорошо подходит для кэшей, конфигураций, логирования, и всего, что должно быть единым.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Для получения значения по ключу в словаре (
Dictionary<TKey, TValue>) используются методы и свойства, такие как индексатор [], метод TryGetValue, и метод ContainsKey. Индексатор позволяет получить значение по ключу напрямую. Если ключ отсутствует в словаре, будет выброшено исключение
KeyNotFoundException.var dictionary = new Dictionary<int, string>
{
{ 1, "One" },
{ 2, "Two" },
{ 3, "Three" }
};
try
{
string value = dictionary[2]; // Получение значения по ключу 2
Console.WriteLine(value); // Выведет "Two"
}
catch (KeyNotFoundException)
{
Console.WriteLine("Key not found");
}
Метод
TryGetValue позволяет безопасно получить значение по ключу. Он возвращает true, если ключ найден, и false, если ключ отсутствует. При этом значение записывается в выходной параметр.var dictionary = new Dictionary<int, string>
{
{ 1, "One" },
{ 2, "Two" },
{ 3, "Three" }
};
if (dictionary.TryGetValue(2, out string value))
{
Console.WriteLine(value); // Выведет "Two"
}
else
{
Console.WriteLine("Key not found");
}
Метод
ContainsKey проверяет наличие ключа в словаре. Его можно использовать в сочетании с индексатором для получения значения.var dictionary = new Dictionary<int, string>
{
{ 1, "One" },
{ 2, "Two" },
{ 3, "Three" }
};
if (dictionary.ContainsKey(2))
{
string value = dictionary[2];
Console.WriteLine(value); // Выведет "Two"
}
else
{
Console.WriteLine("Key not found");
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Можно ограничить типы, которые передаются в шаблоны (generics), с помощью ключевого слова
where. Это позволяет указать, какие типы подходят для использования, обеспечивая безопасность и предсказуемость кода. Вот основные виды ограничений:where T : class — только классы. where T : struct — только структуры.Указание интерфейса, который должен реализовать тип:
public class MyClass<T> where T : IDisposable { }
Указание, что тип должен быть наследником определённого класса:
public class MyClass<T> where T : Exception { }
Ограничение на наличие конструктора без параметров:
public class MyClass<T> where T : new() { }
Можно объединять несколько условий:
public class MyClass<T> where T : class, IDisposable, new() { }Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Используется для объявления небезопасного контекста кода, который позволяет выполнять низкоуровневые операции, такие как манипуляции с указателями. Эти операции обычно не разрешены в безопасном управляемом коде, но могут быть необходимы для взаимодействия с неуправляемым кодом, оптимизации производительности или доступа к определенным системным ресурсам.
Чтобы использовать указатели и выполнять небезопасные операции, нужно объявить метод, блок кода или тип как
unsafe. unsafe void UnsafeMethod()
{
int a = 10;
int* p = &a; // Использование указателя
Console.WriteLine(*p); // Разыменование указателя
}
Для компиляции кода с
unsafe необходимо включить поддержку небезопасного кода в настройках проекта. В Visual Studio это делается через свойства проекта:Указатели позволяют напрямую работать с адресами памяти, что может быть полезно для некоторых оптимизаций или взаимодействия с низкоуровневым кодом, написанным на C или C++.
unsafe void PointerExample()
{
int a = 5;
int* p = &a; // p указывает на адрес переменной a
Console.WriteLine((int)p); // Вывод адреса переменной a
Console.WriteLine(*p); // Вывод значения переменной a через указатель
}
Вы можете объявлять структуры с указателями и использовать их в небезопасном контексте.
unsafe struct UnsafeStruct
{
public int* Pointer;
}
stackalloc позволяет выделять память в стеке для массива в небезопасном контексте. Это может быть быстрее, чем выделение памяти в куче. unsafe void StackAllocExample()
{
int* array = stackalloc int[10]; // Выделение массива из 10 целых чисел в стеке
for (int i = 0; i < 10; i++)
{
array[i] = i;
}
}
Небезопасный код часто используется для взаимодействия с API, написанными на других языках, такими как C или C++.
[DllImport("user32.dll")]
extern static unsafe int MessageBox(IntPtr hWnd, char* text, char* caption, int options);
unsafe void CallUnmanagedCode()
{
char* text = "Hello, World!";
char* caption = "My Message Box";
MessageBox(IntPtr.Zero, text, caption, 0);
}Позволяет выполнять высокоэффективные операции с памятью.
Необходим для вызова функций из библиотек, написанных на других языках.
Предоставляет возможность прямого управления памятью и аппаратными ресурсами.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Value-типы (значимые типы) хранятся в стеке. При передаче в методы они копируются, то есть метод работает с копией, а не с оригиналом. Примеры: int, float, bool, struct.
Reference-типы (ссылочные типы) хранятся в куче, а в стеке содержится ссылка на объект. При передаче в метод передаётся ссылка, и метод работает с тем же объектом. Примеры: class, string, object, массивы.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это структура данных, используемая в системах управления базами данных (СУБД) для организации и ускорения доступа к данным. B-tree индекс является сбалансированным деревом, обеспечивающим эффективное выполнение операций поиска, вставки, удаления и диапазонного поиска. B-tree индекс используется большинством реляционных СУБД, таких как SQL Server, MySQL, PostgreSQL и Oracle.
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
👍2
В .NET добавление сторонней библиотеки может происходить несколькими способами:
- Через NuGet-пакет:
- Используя команду: dotnet add package <PackageName>
- Или через Visual Studio — «Manage NuGet Packages».
- Через ссылку на DLL:
- Скопировать .dll файл и добавить его через «Add Reference».
- Через проектную ссылку:
- Если у тебя есть другой .csproj, его можно подключить как зависимость.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Dispose и Finalize являются двумя механизмами для управления ресурсами, особенно теми, которые не управляются средой выполнения .NET, такими как файловые дескрипторы или соединения с базой данных. Они играют важную роль в освобождении ресурсов, но работают по-разному.
Можно переопределить в классе для выполнения очистки ресурсов перед тем, как объект будет собран сборщиком мусора. Этот метод вызывается сборщиком мусора автоматически, если объект уничтожается и не имеет других живых ссылок.
Является частью интерфейса
IDisposable и предоставляет явный способ освобождения управляемых и неуправляемых ресурсов. Разработчики могут вызывать Dispose вручную или использовать конструкцию using, которая гарантирует вызов Dispose по завершении блока кода.public class ResourceHolder : IDisposable
{
private bool disposed = false;
~ResourceHolder() // Финализатор
{
Dispose(false);
}
public void Dispose() // Метод Dispose из IDisposable
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Освобождение управляемых ресурсов
}
// Освобождение неуправляемых ресурсов
disposed = true;
}
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ключевое слово using используется в двух основных контекстах: для управления областью видимости объектов, реализующих интерфейс
IDisposable, и для включения пространств имён.Можно использовать для создания блока кода, внутри которого объекты, реализующие интерфейс
IDisposable, автоматически освобождаются по завершении блока. Это удобно для управления ресурсами, такими как файловые потоки, базы данных или другие ресурсы системы, которые требуют явного освобождения.using (StreamWriter writer = new StreamWriter("example.txt"))
{
writer.WriteLine("Hello, world!");
}
// Здесь объект writer уже автоматически закрыт и освобожден.Также используется для объявления пространств имен, которые будут использоваться в коде, позволяя обращаться к классам внутри этих пространств без полного указания их имён.
using System;
using System.IO;
using System.Text;
// Теперь можно использовать классы из System, System.IO и System.Text без полного указания имени.
Для включения статических классов, что позволяет обращаться к статическим членам класса напрямую без указания имени класса.
using static System.Console;
using static System.Math;
class Program
{
static void Main()
{
WriteLine(Sqrt(144)); // Использование метода WriteLine и Sqrt без указания классов Console и Math
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
using — это удобная конструкция, которая автоматически вызывает Dispose, когда объект больше не нужен.
Под капотом она разворачивается в блок с вызовом Dispose в конце, даже если произошла ошибка. Это защищает от утечек ресурсов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Используются для выполнения логики до и после выполнения метода действия контроллера. Они предоставляют механизм для выполнения кросс-секционных задач, таких как логирование, обработка исключений, валидация и т.д. Action фильтры реализуют интерфейс
IActionFilter или IAsyncActionFilter.Этот метод вызывается перед выполнением метода действия. Здесь можно добавить логику, которая будет выполняться до вызова действия, например, логирование или проверка условий.
public void OnActionExecuting(ActionExecutingContext context)
{
// Логика до выполнения действия
}
Этот метод вызывается после выполнения метода действия. Здесь можно добавить логику, которая будет выполняться после вызова действия, например, логирование результатов или модификация ответа.
public void OnActionExecuted(ActionExecutedContext context)
{
// Логика после выполнения действия
}
Этот метод объединяет функциональность
OnActionExecuting и OnActionExecuted в одном асинхронном методе. Здесь можно определить логику, которая будет выполняться как до, так и после выполнения метода действия.public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Логика до выполнения действия
var resultContext = await next();
// Логика после выполнения действия
}
Синхронный Action фильтр:
public class SampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Логика до выполнения действия
Console.WriteLine("Before executing action");
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Логика после выполнения действия
Console.WriteLine("After executing action");
}
}
Асинхронный Action фильтр:
public class SampleAsyncActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Логика до выполнения действия
Console.WriteLine("Before executing action");
var resultContext = await next();
// Логика после выполнения действия
Console.WriteLine("After executing action");
}
}
Action фильтр можно применять к контроллерам или действиям контроллера с помощью атрибута
[ServiceFilter] или [TypeFilter]. Также его можно зарегистрировать глобально в Startup.cs.Применение к контроллеру или действию:
[ServiceFilter(typeof(SampleActionFilter))]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
Глобальная регистрация:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(config =>
{
config.Filters.Add(typeof(SampleActionFilter));
});
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
В ASP.NET Core методы Service Configuration используются для настройки и регистрации зависимостей в контейнере внедрения зависимостей (Dependency Injection, DI). Это позволяет управлять зависимостями в приложении, делая код более гибким, тестируемым и удобным для расширения.
Настройка сервисов выполняется в методе
ConfigureServices(IServiceCollection services), который находится в классе Program.cs или Startup.cs (в зависимости от версии .NET). public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(); // Добавление контроллеров для API
services.AddDbContext<ApplicationDbContext>(); // Регистрация контекста базы данных
services.AddScoped<IMyService, MyService>(); // Внедрение зависимости
}
создаёт единственный экземпляр объекта на всё время работы приложения.
services.AddSingleton<ILogger, ConsoleLogger>();
создаёт один экземпляр объекта на каждый HTTP-запрос.
services.AddScoped<IUserService, UserService>();
создаёт новый экземпляр объекта при каждом запросе.
services.AddTransient<IEmailSender, EmailSender>();
public class HomeController : Controller
{
private readonly IMyService _myService;
public HomeController(IMyService myService)
{
_myService = myService;
}
public IActionResult Index()
{
var data = _myService.GetData();
return View(data);
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM