Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🤯2🔥1
В веб-приложениях, например, в ASP.NET Core, обрабатывает HTTP-запросы и формирует HTTP-ответы. Каждое middleware-компонент выполняет свою работу и передает управление следующему компоненту в конвейере или завершает обработку и формирует ответ.
Middleware получает запрос и может его обработать частично или полностью.
Если middleware не формирует окончательный ответ, оно вызывает следующий компонент в конвейере.
Middleware может завершить обработку запроса, сформировав ответ, или пропустить управление следующему компоненту.
Простое middleware
public class SimpleMiddleware
{
private readonly RequestDelegate _next;
public SimpleMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
// Обработка запроса до следующего middleware
Console.WriteLine("Handling request.");
// Передача управления следующему middleware в конвейере
await _next(context);
// Обработка ответа после следующего middleware
Console.WriteLine("Handling response.");
}
}
Регистрация middleware в конвейере
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMiddleware<SimpleMiddleware>();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello, World!");
});
}
Middleware может завершить обработку запроса и сразу вернуть ответ. Например, проверка аутентификации может вернуть 401 Unauthorized.
public class AuthMiddleware
{
private readonly RequestDelegate _next;
public AuthMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (!context.User.Identity.IsAuthenticated)
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsync("Unauthorized");
return; // Завершаем обработку, не вызывая _next
}
await _next(context);
}
}
Если middleware вызывает следующий компонент в конвейере, то окончательный ответ может быть сформирован этим компонентом или одним из последующих.
public class LoggingMiddleware
{
private readonly RequestDelegate _next;
public LoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
// Логирование до обработки запроса
Console.WriteLine("Request incoming");
await _next(context);
// Логирование после обработки запроса
Console.WriteLine("Response outgoing");
}
}
Middleware компоненты вызываются последовательно, в том порядке, в котором они зарегистрированы в
Configure.Каждый middleware может передать управление следующему компоненту или завершить обработку, вернув ответ.
После вызова следующего middleware текущий компонент может выполнять дополнительные действия с ответом (например, логирование).
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤1🔥1
Это паттерн проектирования поведенческих шаблонов, который позволяет уменьшить связанность между объектами, обеспечивая взаимодействие через центральный объект-посредник. Медиатор упрощает коммуникацию между компонентами системы, делая ее более модульной и легкой для сопровождения.
public interface IMediator
{
void Notify(object sender, string ev);
}
public class DialogMediator : IMediator
{
private Button _button;
private TextBox _textBox;
public DialogMediator(Button button, TextBox textBox)
{
_button = button;
_button.SetMediator(this);
_textBox = textBox;
_textBox.SetMediator(this);
}
public void Notify(object sender, string ev)
{
if (ev == "ButtonClick")
{
_textBox.Clear();
}
else if (ev == "TextBoxEnter")
{
_button.SetEnabled(true);
}
}
}
public class Button
{
private IMediator _mediator;
public void SetMediator(IMediator mediator)
{
_mediator = mediator;
}
public void Click()
{
Console.WriteLine("Button clicked");
_mediator.Notify(this, "ButtonClick");
}
public void SetEnabled(bool enabled)
{
Console.WriteLine($"Button is {(enabled ? "enabled" : "disabled")}");
}
}
public class TextBox
{
private IMediator _mediator;
public void SetMediator(IMediator mediator)
{
_mediator = mediator;
}
public void EnterText()
{
Console.WriteLine("Text entered");
_mediator.Notify(this, "TextBoxEnter");
}
public void Clear()
{
Console.WriteLine("TextBox cleared");
}
}
var button = new Button();
var textBox = new TextBox();
var mediator = new DialogMediator(button, textBox);
textBox.EnterText(); // Ввод текста активирует кнопку
button.Click(); // Нажатие кнопки очищает текстовое поле
Компоненты не взаимодействуют напрямую, а используют медиатор.
Вся логика взаимодействия сосредоточена в одном месте.
Легко добавлять новые компоненты или изменять существующие.
Медиатор может стать сложным, если в него добавляется много логики.
Если медиатор выходит из строя, это может повлиять на всю систему.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
В Entity Framework (EF)
join операции используются для объединения данных из нескольких таблиц на основе связанных полей. В EF можно использовать как метод синтаксиса, так и синтаксис запросов (LINQ). Рассмотрим оба подхода на примерах.Метод синтаксиса предоставляет методы расширения для выполнения
join операций. Допустим, у нас есть две сущности: Student и Enrollment, где Enrollment содержит StudentId, который является внешним ключом, связывающим эти две сущности. public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
}
public class Enrollment
{
public int EnrollmentId { get; set; }
public int StudentId { get; set; }
public string Course { get; set; }
}
Использование метода синтаксиса
using (var context = new SchoolContext())
{
var query = context.Students
.Join(context.Enrollments,
student => student.StudentId,
enrollment => enrollment.StudentId,
(student, enrollment) => new
{
StudentName = student.Name,
Course = enrollment.Course
})
.ToList();
foreach (var item in query)
{
Console.WriteLine($"Student: {item.StudentName}, Course: {item.Course}");
}
}
Синтаксис запросов использует выражения LINQ, которые похожи на SQL-запросы. Тот же пример с
Student и Enrollment, но с использованием синтаксиса запросов. using (var context = new SchoolContext())
{
var query = (from student in context.Students
join enrollment in context.Enrollments
on student.StudentId equals enrollment.StudentId
select new
{
StudentName = student.Name,
Course = enrollment.Course
}).ToList();
foreach (var item in query)
{
Console.WriteLine($"Student: {item.StudentName}, Course: {item.Course}");
}
}
Соединяет строки из двух таблиц, когда есть совпадения по ключу.
Возвращает все строки из левой таблицы и совпадающие строки из правой таблицы. Если совпадений нет, результатом будет
null для правой таблицы.using (var context = new SchoolContext())
{
var query = from student in context.Students
join enrollment in context.Enrollments
on student.StudentId equals enrollment.StudentId
into studentEnrollments
from se in studentEnrollments.DefaultIfEmpty()
select new
{
StudentName = student.Name,
Course = se?.Course ?? "No Course"
};
foreach (var item in query.ToList())
{
Console.WriteLine($"Student: {item.StudentName}, Course: {item.Course}");
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔6👍4❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥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
👍7❤2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Чтобы сравнить коллекции по содержимому в C#, необходимо убедиться, что сравнение выполняется на основе значений элементов, а не ссылок на объекты. Существуют различные способы сделать это, в зависимости от типа коллекций и их содержимого.
Использование `SequenceEqual`
Этот метод сравнивает две последовательности (например, списки или массивы) на основе значений элементов. Поддерживает опциональный параметр
IEqualityComparer<T> для пользовательского сравнения.using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 1, 2, 3 };
var list3 = new List<int> { 3, 2, 1 };
bool areEqual = list1.SequenceEqual(list2); // True
bool areEqualDifferentOrder = list1.SequenceEqual(list3); // False
Console.WriteLine(areEqual);
Console.WriteLine(areEqualDifferentOrder);
}
}
Для сравнения коллекций сложных объектов можно использовать
IEqualityComparer<T>.using System;
using System.Collections.Generic;
using System.Linq;
public class Person
{
public string Name { 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 Name == other.Name && Age == other.Age;
}
public override int GetHashCode()
{
return HashCode.Combine(Name, Age);
}
}
public class PersonEqualityComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
if (x == null || y == null)
return false;
return x.Name == y.Name && x.Age == y.Age;
}
public int GetHashCode(Person obj)
{
return obj.GetHashCode();
}
}
public class Program
{
public static void Main()
{
var list1 = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 25 }
};
var list2 = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 25 }
};
bool areEqual = list1.SequenceEqual(list2, new PersonEqualityComparer()); // True
Console.WriteLine(areEqual);
}
}
Для сравнения unordered коллекций, таких как
HashSet, можно использовать методы SetEquals.using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var set1 = new HashSet<int> { 1, 2, 3 };
var set2 = new HashSet<int> { 3, 2, 1 };
bool areEqual = set1.SetEquals(set2); // True
Console.WriteLine(areEqual);
}
}
Для сравнения словарей можно сравнивать их ключи и значения.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥3
Для того чтобы использовать экземпляры класса в качестве ключей в коллекциях, таких как
Dictionary<TKey, TValue>, HashSet<T>, или других коллекциях, требующих уникальных ключей, необходимо обеспечить правильное поведение методов GetHashCode и Equals. Эти методы используются для определения уникальности и сравнения объектов.Этот метод должен возвращать хеш-код для объекта. Хеш-код должен быть одинаковым для объектов, которые считаются равными.
Этот метод должен определять, равны ли два объекта. Он должен сравнивать значения всех полей, которые определяют уникальность объекта.
Реализация
IEquatable<T> может улучшить производительность и предоставить более явный контракт для сравнения объектов.public class Person : IEquatable<Person>
{
public string Name { get; set; }
public int Age { get; set; }
// Переопределение Equals
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;
Person other = (Person)obj;
return Name == other.Name && Age == other.Age;
}
// Реализация IEquatable<Person>.Equals
public bool Equals(Person other)
{
if (other == null)
return false;
return Name == other.Name && Age == other.Age;
}
// Переопределение GetHashCode
public override int GetHashCode()
{
return HashCode.Combine(Name, Age);
}
}
Использование класса в качестве ключа в словаре
public class Program
{
public static void Main()
{
var personDictionary = new Dictionary<Person, string>();
var person1 = new Person { Name = "Alice", Age = 30 };
var person2 = new Person { Name = "Bob", Age = 25 };
personDictionary[person1] = "Engineer";
personDictionary[person2] = "Doctor";
// Поиск по ключу
if (personDictionary.TryGetValue(new Person { Name = "Alice", Age = 30 }, out string profession))
{
Console.WriteLine($"Alice's profession is {profession}");
}
}
}
Метод
Equals должен возвращать true для объектов, которые считаются равными. Сравнивайте все значимые поля объекта.Метод
GetHashCode должен возвращать одинаковые хеш-коды для объектов, которые считаются равными. Используйте комбинацию значимых полей для вычисления хеш-кода. В .NET Core и .NET 5+ рекомендуется использовать HashCode.Combine.Реализация интерфейса
IEquatable<T> улучшает производительность и ясность кода. Метод Equals(T other) должен содержать ту же логику, что и Equals(object obj).Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Для получения значения по ключу в словаре (
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
👍5
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Должен возвращать целое число (
int), которое представляет хеш-код объекта. Этот хеш-код используется структурами данных, такими как хеш-таблицы (например, Dictionary<TKey, TValue>, HashSet<T>), для быстрого поиска, вставки и удаления объектов.Если два объекта равны (по методу
Equals), то их хеш-коды должны быть одинаковыми. Если Equals возвращает true для двух объектов, их 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
👍4❤2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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 0.
Содержит объекты с самым длительным временем жизни. Наибольший размер среди всех поколений. Сборка мусора для этого поколения происходит реже всего.
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 среде управления памятью существуют несколько типов куч, каждая из которых предназначена для различных типов объектов и оптимизации производительности управления памятью.
Это основная область памяти, используемая средой выполнения .NET для управления динамически выделенной памятью. Она разделена на поколения для оптимизации производительности сборки мусора.
Содержит новосозданные объекты. Сборка мусора в этом поколении происходит чаще всего. Маленький размер, рассчитанный на быстрое освобождение памяти от краткоживущих объектов.
Промежуточное поколение. Объекты, которые пережили сборку мусора в Generation 0, перемещаются в Generation 1. Средний размер, служит буфером между краткоживущими и долгоживущими объектами.
Содержит объекты с длительным временем жизни. Объекты, которые пережили сборку мусора в 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
}
}
Куча больших объектов используется для размещения крупных объектов (размером 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
}
}
Сегментированные кучи используются в серверной сборке мусора (Server GC), где для каждой логической обработки (ядра процессора) создается отдельная куча:
Позволяет более эффективно использовать многопроцессорные системы.
Каждое ядро работает со своим сегментом памяти, что уменьшает конкуренцию за доступ к памяти.
Упрощенная куча представляет собой комбинацию Generation 0 и Generation 1 и используется для оптимизации управления краткоживущими объектами. Этот термин чаще встречается в контексте описания поведения сборщика мусора.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3