Anonymous Quiz
84%
Метод для очистки ресурсов, объявляется с помощью символа ~
12%
Метод для сериализации, объявляется с помощью ключевого слова final
2%
Метод для логирования, объявляется с помощью символа #
2%
Метод для отладки, объявляется с помощью ключевого слова debug
Паттерн DDD (Domain-Driven Design, предметно-ориентированное проектирование) — это методология разработки программного обеспечения, которая фокусируется на сложных предметных областях и переводе их в код. Основная идея DDD заключается в том, чтобы создать программные модели, которые соответствуют бизнес-логике и терминологии, используемой экспертами в данной предметной области.
Сущности и объекты-значения
// Value Object
public class Money
{
public decimal Amount { get; }
public string Currency { get; }
public Money(decimal amount, string currency)
{
Amount = amount;
Currency = currency;
}
public override bool Equals(object obj)
{
if (obj is Money money)
{
return Amount == money.Amount && Currency == money.Currency;
}
return false;
}
public override int GetHashCode() => (Amount, Currency).GetHashCode();
}
// Entity
public class Product
{
public Guid Id { get; }
public string Name { get; private set; }
public Money Price { get; private set; }
public Product(Guid id, string name, Money price)
{
Id = id;
Name = name;
Price = price;
}
public void Rename(string newName)
{
Name = newName;
}
public void ChangePrice(Money newPrice)
{
Price = newPrice;
}
}
Преимущества
Недостатки
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥2
Anonymous Quiz
84%
Array имеет фиксированный размер, ArrayList динамически изменяет размер.
7%
Array поддерживает любые типы данных, ArrayList только объекты.
4%
Array не поддерживает индексацию, ArrayList поддерживает.
6%
Array поддерживает обобщения, ArrayList не поддерживает.
Паттерн Event Sourcing (событийное моделирование) — это подход к управлению состоянием приложения, при котором все изменения состояния представляются в виде последовательности событий. Вместо хранения текущего состояния объекта в базе данных, сохраняются все изменения состояния (события), которые произошли с этим объектом. Текущее состояние может быть восстановлено путем последовательного применения этих событий.
public class AccountCreated
{
public Guid AccountId { get; }
public string Owner { get; }
public AccountCreated(Guid accountId, string owner)
{
AccountId = accountId;
Owner = owner;
}
}
public class MoneyDeposited
{
public Guid AccountId { get; }
public decimal Amount { get; }
public MoneyDeposited(Guid accountId, decimal amount)
{
AccountId = accountId;
Amount = amount;
}
}
public class MoneyWithdrawn
{
public Guid AccountId { get; }
public decimal Amount { get; }
public MoneyWithdrawn(Guid accountId, decimal amount)
{
AccountId = accountId;
Amount = amount;
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Anonymous Quiz
72%
Поле, значение которого можно установить только при инициализации или в конструкторе.
15%
Поле, значение которого нельзя изменить после присвоения.
10%
Метод, который можно вызвать только для чтения данных.
2%
Свойство, которое можно только установить, но не прочитать.
Основные концепции
Преимущества
Недостатки
Команда (Command)
public class CreateUserCommand
{
public string Name { get; }
public CreateUserCommand(string name)
{
Name = name;
}
}
Обработчик команды (Command Handler)
public class CreateUserCommandHandler
{
private readonly UserDbContext _context;
public CreateUserCommandHandler(UserDbContext context)
{
_context = context;
}
public void Handle(CreateUserCommand command)
{
var user = new User { Name = command.Name };
_context.Users.Add(user);
_context.SaveChanges();
}
}
Запрос (Query)
public class GetUserQuery
{
public int UserId { get; }
public GetUserQuery(int userId)
{
UserId = userId;
}
}
Обработчик запроса (Query Handler)
public class GetUserQueryHandler
{
private readonly UserDbContext _context;
public GetUserQueryHandler(UserDbContext context)
{
_context = context;
}
public User Handle(GetUserQuery query)
{
return _context.Users.Find(query.UserId);
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤1
Anonymous Quiz
27%
private
62%
protected
10%
internal
1%
public
🔥8😁2
Микросервис — это архитектурный стиль, который предполагает создание приложения в виде набора небольших, автономных сервисов, каждый из которых отвечает за выполнение конкретной бизнес-функции. Эти сервисы могут разрабатываться, развёртываться и масштабироваться независимо друг от друга.
Преимущества микросервисов
Недостатки микросервисов
Каждый из этих микросервисов имеет своё собственное API и базу данных.
// Пример простого контроллера для микросервиса пользователя
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
[HttpGet("{id}")]
public ActionResult<User> GetUser(int id)
{
var user = _userService.GetUserById(id);
if (user == null)
{
return NotFound();
}
return Ok(user);
}
[HttpPost]
public ActionResult<User> CreateUser([FromBody] User user)
{
var createdUser = _userService.CreateUser(user);
return CreatedAtAction(nameof(GetUser), new { id = createdUser.Id }, createdUser);
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20
Anonymous Quiz
92%
Позволяют писать код, работающий с любыми типами данных.
5%
Позволяют сериализовать данные.
2%
Используются для работы с базами данных.
1%
Обеспечивают логирование приложений.
Легко масштабировать только те части системы, которые требуют этого, без необходимости масштабировать всё приложение. Например, если у вас есть микросервис, обрабатывающий заказы, и он испытывает высокую нагрузку, вы можете масштабировать только его, не трогая другие части системы.
Микросервисы можно развёртывать, обновлять и откатывать независимо друг от друга. Например вы можете обновить микросервис аутентификации без остановки микросервиса каталога продуктов.
Отказ одного микросервиса не приводит к отказу всего приложения. Например, если микросервис обработки платежей выходит из строя, пользователи всё равно могут просматривать продукты и добавлять их в корзину.
Каждый микросервис может быть написан на своем языке программирования и использовать свои технологии, что позволяет выбирать наиболее подходящие инструменты для каждой задачи. Например, Вы можете использовать Python для микросервиса машинного обучения и .NET для микросервиса управления пользователями.
Малые команды могут работать над разными микросервисами параллельно, что ускоряет процесс разработки. Например, одна команда может работать над микросервисом управления пользователями, в то время как другая команда работает над микросервисом заказа.
Управление множеством микросервисов требует сложной инфраструктуры для оркестрации, мониторинга и логирования. Например, вам нужно внедрить систему оркестрации, такую как Kubernetes, чтобы управлять развертыванием и масштабированием микросервисов.
Необходимо наладить надежные межсервисные коммуникации, что может быть сложно и привести к повышенным накладным расходам. Например, вам нужно решить, использовать ли синхронные (HTTP/REST) или асинхронные (сообщения, очереди) методы связи между микросервисами.
Тестирование микросервисной архитектуры сложнее из-за необходимости интеграции и взаимодействия между множеством независимых компонентов. Например вам нужно создать среду для интеграционного тестирования, которая включает все необходимые микросервисы.
Согласованность данных и управление транзакциями становятся более сложными задачами в распределённой системе. Например, вам нужно внедрить сложные механизмы для обеспечения согласованности данных, такие как саги или распределённые транзакции.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Anonymous Quiz
71%
var dict = new Dictionary<int, string>();
16%
Dictionary<int, string> dict = new Dictionary();
3%
var dict = new Dictionary<int>();
11%
Dictionary dict = new Dictionary<int, string>();
🤯16🤔1👾1
Паттерн "Разделяй и властвуй" (Divide and Conquer) разделяет задачи на более мелкие подзадачи для упрощения кода и повышения эффективности.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤯2
Anonymous Quiz
50%
var name = obj?.ToString();
10%
var name = obj?.Name();
32%
var name = obj?.Name;
7%
var name = obj?.GetName;
🤔9👍2👀1
Records:
Предназначены для создания неизменяемых типов данных с минимальным шаблонным кодом
public record Person(string FirstName, string LastName);
Init-only Properties:
Позволяют устанавливать значения свойств только при инициализации объекта.
public class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
With-expressions:
Используются для создания копий неизменяемых объектов с изменёнными значениями.
var person1 = new Person("John", "Doe");
var person2 = person1 with { LastName = "Smith" };Top-level Statements:
Позволяют писать код без явного класса или метода
Main.using System;
Console.WriteLine("Hello, World!");
Pattern Matching Enhancements:
Улучшения в сопоставлении с образцом, включая логические шаблоны (
and, or, not) и шаблоны типа is.if (person is Person { FirstName: "John", LastName: "Doe" })
{
Console.WriteLine("It's John Doe!");
} Global using directives:
Позволяют объявлять
using директивы, применимые ко всему проекту.// В globalusing.cs
global using System;
global using System.Collections.Generic;
File-scoped Namespace:
Упрощённый синтаксис для объявления пространства имён для всего файла.
namespace MyNamespace;
class MyClass { }
Record Structs:
Записи, которые могут быть значимыми типами.
public record struct Point(int X, int Y);
Improved `lambda` expressions:
Улучшения в синтаксисе и типизации лямбда-выражений.
Func<int, int> square = x => x * x;
Required Members:
Обязательные члены, которые должны быть установлены при создании объекта.
public class Person
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
}
Raw String Literals:
Упрощённый синтаксис для создания многострочных строковых литералов без экранирования.
var json = """
{
"name": "John Doe",
"age": 30
}
""";
Generic Attributes:
Позволяют создавать атрибуты с обобщёнными параметрами.
[AttributeUsage(AttributeTargets.Class)]
public class MyGenericAttribute<T> : Attribute { }
[MyGenericAttribute<int>]
public class MyClass { }
List Pattern Matching:
Сопоставление с образцом для списков.
if (numbers is [1, 2, .., 10])
{
Console.WriteLine("The list starts with 1, 2 and ends with 10.");
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31❤2
Anonymous Quiz
78%
public async Task<int> GetData() { return await Task.FromResult(42); }
3%
public async int GetData() { return 42; }
13%
public Task<int> GetData() { return Task.FromResult(42); }
5%
public async Task GetData() { return 42; }
🤯7
Для оптимизации LINQ запросов в C# используйте компилируемые запросы, минимизируйте запросы в циклах, выбирайте только нужные поля, применяйте отложенное выполнение и метод
.AsNoTracking() для чтения данных.LINQ-запросы не выполняются до тех пор, пока не начнётся итерация по ним. Это позволяет объединить несколько операций в один запрос к базе данных.
var query = dbContext.Users.Where(u => u.IsActive); // Запрос ещё не выполнен
var activeUsers = query.ToList(); // Запрос выполнен здесь
Избегайте ненужных вызовов
ToList и ToArray, так как они приводят к немедленному выполнению запроса и загрузке всех данных в память.var users = dbContext.Users.Where(u => u.IsActive).ToList(); // Не вызывайте ToList() до тех пор, пока не нужно
Выбирайте только необходимые поля, чтобы уменьшить объем данных, передаваемых по сети и загружаемых в память.
var userNames = dbContext.Users
.Where(u => u.IsActive)
.Select(u => new { u.FirstName, u.LastName })
.ToList();
Фильтруйте данные на уровне базы данных, а не в памяти, чтобы уменьшить количество передаваемых данных.
var activeUsers = dbContext.Users.Where(u => u.IsActive).ToList(); // Фильтрация на уровне базы данных
Используйте пагинацию для работы с большими наборами данных, чтобы загружать и обрабатывать только нужные страницы.
var pageNumber = 2;
var pageSize = 10;
var paginatedUsers = dbContext.Users
.Where(u => u.IsActive)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.ToList();
Сложные LINQ-запросы в циклах могут привести к многочисленным запросам к базе данных. Постарайтесь минимизировать их или объединить в один запрос.
// Плохо
foreach (var userId in userIds)
{
var user = dbContext.Users.FirstOrDefault(u => u.Id == userId);
}
// Хорошо
var users = dbContext.Users.Where(u => userIds.Contains(u.Id)).ToList();
Асинхронные методы, такие как
ToListAsync, FirstOrDefaultAsync и SingleOrDefaultAsync, помогают избежать блокировки потоков и улучшить производительность.var activeUsers = await dbContext.Users.Where(u => u.IsActive).ToListAsync();
Для часто выполняемых запросов используйте
EF.CompileQuery в Entity Framework, чтобы уменьшить накладные расходы на компиляцию запросов.private static readonly Func<MyDbContext, bool, IQueryable<User>> GetActiveUsersQuery =
EF.CompileQuery((MyDbContext context, bool isActive) =>
context.Users.Where(u => u.IsActive == isActive));
var activeUsers = GetActiveUsersQuery(dbContext, true).ToList();
Используйте инструменты профилирования и логирования для анализа генерируемых SQL-запросов, чтобы найти потенциальные узкие места и неэффективные запросы.
var sql = dbContext.Users.Where(u => u.IsActive).ToQueryString();
Console.WriteLine(sql);
Убедитесь, что индексы в базе данных настроены правильно для часто выполняемых запросов, чтобы улучшить производительность поиска.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25
Anonymous Quiz
59%
var tuple = new Tuple<int, string>(1, "one");
9%
var tuple = Tuple.Create(1, "one");
12%
var tuple = new Tuple(1, "one");
20%
var tuple = (1, "one");
👍6👀5🤔3😁2
Обработка исключений в C# необходима для правильного управления ошибками, возникающими во время выполнения программы. Она позволяет перехватывать ошибки и выполнять соответствующие действия, чтобы программа не завершалась аварийно. Рассмотрим основные конструкции для обработки исключений:
try, catch, finally, и throw.Конструкция
try-catch используется для перехвата и обработки исключений. Код, который может вызвать исключение, помещается в блок try, а код для обработки исключения - в блок catch. try
{
// Код, который может вызвать исключение
int result = 10 / 0;
}
catch (DivideByZeroException ex)
{
// Обработка исключения
Console.WriteLine("Произошло деление на ноль: " + ex.Message);
}
catch (Exception ex)
{
// Обработка других исключений
Console.WriteLine("Произошла ошибка: " + ex.Message);
}
Блок
finally выполняется в любом случае после завершения блоков try и catch, независимо от того, возникло исключение или нет. Он часто используется для освобождения ресурсов, таких как файловые дескрипторы или сетевые подключения. try
{
// Код, который может вызвать исключение
using (StreamReader sr = new StreamReader("file.txt"))
{
// Чтение файла
}
}
catch (FileNotFoundException ex)
{
// Обработка исключения
Console.WriteLine("Файл не найден: " + ex.Message);
}
finally
{
// Очистка ресурсов
Console.WriteLine("Закрытие файла.");
}
Ключевое слово
throw используется для генерации исключений. Оно может быть использовано как для передачи возникшего исключения дальше по цепочке вызовов, так и для создания нового исключения. void ProcessNumber(int number)
{
if (number < 0)
{
throw new ArgumentOutOfRangeException("number", "Число должно быть неотрицательным");
}
// Продолжение обработки
}
Вложенные исключения позволяют захватывать одно исключение и генерировать новое, сохраняя информацию о первоначальном исключении.
try
{
// Код, который может вызвать исключение
MethodThatThrows();
}
catch (Exception ex)
{
throw new InvalidOperationException("Ошибка в процессе выполнения", ex);
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Anonymous Quiz
13%
var result = from x in list where x > 10;
5%
var result = list.Find(x => x > 10);
8%
var result = list.Filter(x => x > 10);
75%
var result = list.Where(x => x > 10);
🤯7
Использование специализированных исключений, таких как
ArgumentException, InvalidOperationException, или пользовательских исключений (например, MyCustomException), лучше, чем использование общего исключения Exception. Это позволяет более точно и детально управлять ошибками.Специализированные исключения помогают точнее определить, что именно пошло не так. Например,
ArgumentNullException ясно указывает, что переданный аргумент был null, в то время как Exception может означать любую ошибку. void ProcessData(string data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data), "Data cannot be null");
}
// Обработка данных
}
Использование конкретных исключений делает код более читаемым и поддерживаемым. Разработчики, читающие код, сразу понимают, какие именно ошибки могут возникнуть и как с ними справляться.
try
{
// Код, который может вызвать исключение
}
catch (ArgumentNullException ex)
{
// Обработка ситуации, когда аргумент был null
}
catch (InvalidOperationException ex)
{
// Обработка некорректного состояния операции
}
Специализированные исключения предоставляют больше информации для отладки. Это позволяет быстрее найти и исправить ошибки, так как разработчики получают более точные сообщения об ошибках.
try
{
// Код, который может вызвать исключение
}
catch (Exception ex)
{
// Общее исключение, трудно определить причину
Console.WriteLine("Произошла ошибка: " + ex.Message);
}
С помощью специализированных исключений можно различать разные типы ошибок и применять к ним разные стратегии обработки. Это делает обработку ошибок более гибкой и точной.
try
{
// Код, который может вызвать исключение
}
catch (ArgumentNullException ex)
{
Console.WriteLine("Обязательный аргумент не был передан: " + ex.Message);
// Специфическая обработка для отсутствующего аргумента
}
catch (ArgumentException ex)
{
Console.WriteLine("Аргумент некорректен: " + ex.Message);
// Специфическая обработка для некорректного аргумента
}
В сложных приложениях можно создавать пользовательские исключения, которые более точно описывают уникальные ошибки, специфичные для вашего приложения.
public class MyCustomException : Exception
{
public MyCustomException(string message) : base(message) { }
}
void DoSomething()
{
throw new MyCustomException("Произошла специфическая ошибка.");
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🤔1🤯1👾1