Регистрация производных классов с помощью отражения, добра или зла? - PullRequest
3 голосов
/ 25 ноября 2008

Как мы все знаем, когда мы выводим класс и используем полиморфизм, кто-то где-то должен знать, какой класс создать. Мы можем использовать фабрики, большой оператор switch, if-else-if и т. Д. Я только что узнал от Bill K, что это называется Dependency Injection.

Мой вопрос: рекомендуется ли использовать отражение и атрибуты в качестве механизма внедрения зависимостей? Таким образом, список динамически заполняется по мере добавления новых типов.

Вот пример . Пожалуйста, не комментируйте, как загрузка изображений может быть сделана другими способами, мы знаем .

Предположим, у нас есть следующий интерфейс IImageFileFormat:

public interface IImageFileFormat
{
   string[] SupportedFormats { get; };
   Image Load(string fileName);
   void Save(Image image, string fileName);
}

Различные классы будут реализовывать этот интерфейс:

[FileFormat]
public class BmpFileFormat : IImageFileFormat { ... }

[FileFormat]
public class JpegFileFormat : IImageFileFormat { ... }

Когда файл должен быть загружен или сохранен, менеджеру необходимо перебрать все известные загрузчики и вызвать Load () / Save () из соответствующего экземпляра в зависимости от их SupportedExtensions.

class ImageLoader
{
   public Image Load(string fileName)
   {
      return FindFormat(fileName).Load(fileName);
   }

   public void Save(Image image, string fileName)
   {
      FindFormat(fileName).Save(image, fileName);
   }

   IImageFileFormat FindFormat(string fileName)
   {
      string extension = Path.GetExtension(fileName);
      return formats.First(f => f.SupportedExtensions.Contains(extension));
   }

   private List<IImageFileFormat> formats;
}

Полагаю, важным моментом здесь является то, должен ли список доступных загрузчиков (форматов) заполняться вручную или с использованием отражения.

От руки:

public ImageLoader()
{
   formats = new List<IImageFileFormat>();
   formats.Add(new BmpFileFormat());
   formats.Add(new JpegFileFormat());
}

По отражению:

public ImageLoader()
{
   formats = new List<IImageFileFormat>();
   foreach(Type type in Assembly.GetExecutingAssembly().GetTypes())
   {
      if(type.GetCustomAttributes(typeof(FileFormatAttribute), false).Length > 0)
      {
         formats.Add(Activator.CreateInstance(type))
      }
   }
}

Я иногда использую последнее, и мне никогда не приходило в голову, что это может быть очень плохой идеей. Да, добавлять новые классы легко, но механизм регистрации тех же классов труднее понять и, следовательно, поддерживать, чем простой закодированный вручную список.

Пожалуйста, обсудите.

Ответы [ 5 ]

4 голосов
/ 25 ноября 2008

Мое личное предпочтение - ни то, ни другое - когда происходит сопоставление классов с какой-либо произвольной строкой, файл конфигурации - это место, где это делается. Таким образом, вам никогда не нужно изменять код - особенно если вы используете механизм динамической загрузки для добавления новых динамических библиотек.

В общем, я всегда предпочитаю какой-либо метод, который позволяет мне писать код как можно чаще - оба ваших метода требуют изменения уже написанного / встроенного / развернутого кода (поскольку ваш путь отражения не предусматривает добавления загрузчиков форматов файлов в новые библиотеки DLL).

Редактирование от Coincoin:

Подход отражения может быть эффективно объединен с файлами конфигурации, чтобы найти имплементации для внедрения.

  • Тип может быть явно объявлен в файле конфигурации с использованием канонических имен, аналогично MSBuild
  • Конфигурация может найти сборки, но затем мы должны внедрить все подходящие типы, например, пакеты Microsoft Visual Studio.
  • Любой другой механизм для сопоставления значения или набора условий необходимому типу.
3 голосов
/ 25 ноября 2008

Мой голос таков, что метод отражения приятнее. С помощью этого метода добавление нового формата файла изменяет только одну часть кода - место, где вы определяете класс для обработки формата файла. Без размышлений вам придется помнить об изменении другого класса, ImageLoader, а также

1 голос
/ 26 ноября 2008

Разве это не в значительной степени то, что представляет собой шаблон внедрения зависимостей?

Если вы можете изолировать зависимости, то механика почти наверняка будет основана на отражениях, но это будет файл конфигурации, управляемый, поэтому запутанность отражений может быть довольно хорошо инкапсулирована и изолирована.

Я полагаю, что с DI вы просто говорите, что мне нужен объект типа <interface> с некоторыми другими параметрами, и система DI возвращает вам объект, который удовлетворяет вашим условиям.

Это идет вместе с IoC (Inversion of Control), где предоставляемому объекту может потребоваться что-то еще, так что другая вещь автоматически создается и устанавливается в ваш объект (создаваемый DI), прежде чем он будет возвращен пользователю.

0 голосов
/ 11 февраля 2011

В vb.net, если все загрузчики изображений будут в одной сборке, можно использовать частичные классы и события для достижения желаемого эффекта (есть класс, целью которого является запуск события, когда загрузчики изображений должны зарегистрировать себя каждый файл, содержащий загрузчики изображений, может использовать «частичный класс» для добавления другого обработчика событий в этот класс); C # не имеет прямого эквивалента синтаксису WithEvents vb.net, но я подозреваю, что частичные классы являются ограниченным механизмом для достижения того же самого.

0 голосов
/ 26 ноября 2008

Я знаю, что это граничит с «без комментариев о загрузке изображений другими способами», но почему бы просто не перевернуть ваши зависимости - вместо того, чтобы ImageLoader зависел от ImageFileFormats, каждый ли объект IImageFileFormat зависел от ImageLoader? Из этого вы получите несколько вещей:

  • Каждый раз, когда вы добавляете новый IImageFileFormat, вам не нужно вносить какие-либо изменения где-либо еще (и вам также не придется использовать отражение)
  • Если вы сделаете еще один шаг вперед и абстрагируете ImageLoader, вы можете смоделировать его в модульных тестах, что значительно упростит тестирование конкретных реализаций каждого IImageFileFormat
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...