Подтвердить что ты не робот

Зачем использовать ImportingConstructor

Я пытаюсь понять, когда [ImportingConstructor] будет более подходящим, чем украшение свойств с помощью [import]. Это личное предпочтение или что-то, что позволяет создавать классы другими контейнерами DI или есть преимущества для [import]?

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

4b9b3361

Ответ 1

Проблема с использованием [Import] заключается в том, что он отделяет создание объекта на две различные и наблюдаемые фазы: созданные и инициализированные. Где [ImportingConstructor] позволяет это оставаться как одна фаза точно так же, как и для любого другого объекта .Net.

Это различие становится наблюдаемым несколькими способами.

  • Добавление нового [Import] в поле изменяет логический контракт типа. Однако это не изменяет публичный или контракт на использование. Это означает, что любой код, который ранее был скомпилирован, будет продолжать компилироваться, даже если изменения объектов изменились (думаю, модульные тесты). Это берет то, что должно быть ошибкой времени компиляции и делает ее временем выполнения.
  • Контракты кода непригодны, если у вас есть [Import]. Механизм проверки контракта правильно распознает, что все поля могут существовать как значения null, и для каждого использования поля требуется проверка.
  • Хотя ваш объект может логически иметь поля, которые установлены во время инициализации и никогда не будут reset, вы не можете выразить это с помощью readonly, как это было бы с обычным объектом С#.

Ответ 2

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

public class MyService
{
  public ILogger Logger { get; set; }

  public void SaySomething()
  {
    Logger.Log("Something");
  }
}

Теперь я мог бы продолжить и создать экземпляр этого:

var service = new MyService();

И теперь, если я попытаюсь использовать метод:

service.SaySomething();

Если я не знаю, что я должен также инициализировать свое свойство Logger:

var service = new MyService() { Logger = new ConsoleLogger() };

(или):

var service = new MyService();
service.Logger = new ConsoleLogger();

Тогда ошибка не станет очевидной до времени выполнения. Если бы мы переопределили класс:

public class MyService
{
  private readonly ILogger _logger;

  public MyService(ILogger logger)
  {
    if (logger == null) throw new ArgumentNullException("logger");

    _logger = logger;
  }

  public void SaySomething()
  {
    _logger.Log("Something");
  }
}

Теперь, если вы попытаетесь создать экземпляр MyService, вы явно должны предоставить эту дополнительную услугу (ILogger) для правильного инициализации объекта. Это помогает нескольким путям:

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

Вы можете улучшить этот дизайн, используя Code Contracts (как указано в @JaredPar), чтобы включить статическую проверку во время компиляции.

В терминах MEF вы можете избежать использования [Import] вместо [ImportingConstructor], поскольку MEF будет генерировать исключение, если он не может удовлетворить все импортные данные в типе, и будет возвращать только тип после обеих инициализаций ([ImportingConstructor]), а затем [Import] s.

Обычно инъекция конструктора предпочтительнее.

Ответ 3

Используя [ImportingConstructor], вы разрешаете одному классу, который служит в качестве экспорта для импорта своих зависимостей. Это значительно упрощает архитектуру, поскольку вы можете отделить зависимости конкретного объекта от его реализации.

Обычно вы используете [ImportingConstructor] для типа, который сам по себе помечен как [Export]. Когда тип составлен, аргументы конструктора будут предоставлены MEF.

Ответ 4

Рекомпозиция также не поддерживается в параметрах конструктора.