Обложка канала

.NET Разработчик

Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин

.NET Разработчик

5 лет назад
Открыть в
День 1097. #BestPractices Лучшие Практики Разработки в C#. Начало Написанию кода можно научиться из онлайн документации или учебника. Однако навыки анализа и проектирования так просто не получить. В этой серии постов рассмотрим некоторые передовые методы проектирования, которые на практике доказали свою эффективность. 1. Унифицированный возвращаемый объект Иногда нужно как-то описать данные, возвращаемые методом. Мы называем это метаданными, так как это не собственно данные, а некоторая важная информация, которая может быть использована позже. Иногда понятно, что метод возвращает какие-то данные, например коллекцию объектов, и некоторые метаданные (общее количество объектов и текущую страницу). Но иногда наличие метаданных не очевидно. Например, метод void RenameFile(string newName) принимает новое имя файла и ничего не возвращает. В реальном мире это может быть проблемой, потому что операция может завершиться неудачей, и тогда метод должен что-то вернуть, чтобы сообщить об этом вызывающей стороне. Я уже слышу ваши варианты: вернуть булевый результат, вернуть новое имя файла в случае успеха или пробросить исключение вызывающему коду. Эти решения могут работать, однако лучше всего здесь вернуть унифицированный объект с некоторыми данными, описывающими, что на самом деле произошло:
public enum FileRenameFailureReason {
  None = 0,
  ExistingName = 1,
  PathTooLong = 2
}

public class FileRenameResult
{
  public FileRenameFailureReason FailureReason { get; }
  public string FinalName { get; }
  public bool Succeeded => 
    FailureReason == FileRenameFailureReason.None;
}

Некоторые преимущества возврата унифицированного объекта: - Перемещение логики туда, где она используется: обработчик хранит логику возврата правильного результата, вызывающий код – логику обработки этого результата (например, выдачи сообщения пользователю). - Определение более чёткого контракта между вызывающим кодом и обработчиком. - Теперь вызывающий код может принимать точные решения на основе полной информации, предоставленной обработчиком. - Работа с унифицированными объектами значительно упрощает разработку общих модулей. 2. Разбиение на страницы Разбиение на страницы — один из широко используемых паттернов, но почти никто не говорит о нём с точки зрения практики проектирования. Когда вы создаёте API, вы должны контролировать объём данных, проходящих через него. Поэтому при разработке API полезно спроектировать стратегию регулирования объема трафика. Вы можете сказать, что у вас нет лимитов, но скорее всего они просто настолько большие, что вы их не осознаёте. Например, если у вас есть метод GetAllEmployees, вы можете разрешить вызывающей стороне получать данные всех сотрудников. А что, если когда-нибудь в системе будет 10 000 сотрудников. Сейчас самое подходящее время вернуть только первые 1000 или 5000 и предоставить вызывающей стороне объект метаданных, сообщающий, что произошло и как получить следующую порцию. 3. Делегаты вместо Func<> Когда нужно определить ссылку на метод, иногда полезнее явно определить делегат, а затем его использовать:
public delegate bool MessageHandler(int id, string msg);

public class Module1
{
  public MessageHandler Handler { get; set; }
}
public class Module2
{
  public Func<int, string, bool> Handler { get; set; }
}

Отличие в том, что вы получите более информативные подсказки в IntelliSense в виде имён параметров вместо arg1, arg2 в случае использования Func<>. Продолжение следует… Источник: levelup.gitconnected.com/design-…b7c3500a