Зарегистрировать тип с помощью конструктора примитивных аргументов? - PullRequest
6 голосов
/ 15 мая 2011

У меня есть класс, в конструкторе которого есть некоторые аргументы примитивного типа, такие как строка и т. Д.

Как мне зарегистрировать тип в контейнере Unity?

public LoginManager(
  IRegionManager regionManager, 
  IEventAggregator eventAggregator, 
  string mainRegionName, 
  Uri login, 
  Uri target)
  {
    this.regionManager = regionManager;
    this.eventAggregator = eventAggregator;
    this.mainRegionName = mainRegionName;
    this.login = login;
    this.target = target;
  }
}

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

Будет ли это считаться вредной привычкой? Есть ли лучшие альтернативы?

Ответы [ 2 ]

15 голосов
/ 16 мая 2011

Старайтесь не иметь дизайн класса, который имеет примитивные или трудно разрешаемые типы в конструкторе. Как вы уже видели из ответа Тавареса, ваша конфигурация становится очень хрупкой ( обновление: Таварес, похоже, удалил свой ответ по причинам, которые мне не ясны ). Вы теряете поддержку времени компиляции, и каждое изменение в этом конструкторе заставляет вас изменять конфигурацию DI.

Существует несколько способов изменить дизайн, чтобы предотвратить это. Какой из них применим для вас, зависит от вас, но вот несколько идей:

Вариант 1: использование неизменяемой конфигурации DTO:

private sealed class LoginManagerConfiguration
{
    public Uri Login { get; private set; }
    public Uri Target { get; private set; }
    public string MainRegionName { get; private set; }

    public LoginManagerConfiguration(Uri login, Uri target, string mainRegionName)
    {
        this.Login = login;
        this.Target = target;
        this.MainRegionName = mainRegionName;
    }
}

Теперь вы можете позволить вашему LoginManager получить зависимость от LoginManagerConfiguration:

public LoginManager(IRegionManager regionManager,
    IEventAggregator eventAggregator,
    LoginManagerConfiguration configuration)
{
    ...
}

LoginManagerConfiguration можно просто зарегистрировать так:

container.RegisterInstance<LoginManagerConfiguration>(
    new LoginManagerConfiguration(
        login: new Uri("Login"),
        target: new Uri("Target"),
        mainRegionName: ConfigurationManager.AppSettings["MainRegion"]));

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

Вариант 2: Производный от этого класса

Другой вариант - наследовать от этого класса только для настройки DI. Это особенно полезно, когда вы не можете изменить сигнатуру класса (т. Е. Когда это сторонний компонент):

private sealed class DILoginManager : LoginManager
{
    DILoginManager(IRegionManager regionManager,
        IEventAggregator eventAggregator)
        : base(regionManager, eventAggregator,
            ConfigurationManager.AppSettings["MainRegion"],
            new Uri("Login"),
            new Uri("Target"))
    {
        ...
    }
}

Определите этот класс близко к корню композиции вашего приложения. Этот класс становится деталью реализации вашей конфигурации DI. Регистрация вашего типа теперь будет очень простой:

container.RegisterType<ILoginManager, DILoginManager>();

Будьте очень осторожны с вызовами, которые лениво загружают значения конфигурации, такие как ConfigurationManager.AppSettings["MainRegion"]. Это может легко привести к ситуациям, когда ошибки конфигурации не обнаруживаются при запуске приложения, что действительно предпочтительно.

Вариант 3: Использовать делегата фабрики

Последний вариант, который я хотел бы представить, это завод. Это будет очень похоже на ответ Traveses, но более безопасно для типов:

var mainRegion = ConfigurationManager.AppSettings["MainRegion"];

container.Register<ILoginManager>(new InjectionFactory(c =>
{
    return new LoginManager(
        c.Resolve<IRegionManager>(),
        c.Resolve<IEventAggregator>(),
        ConfigurationManager.AppSettings["MainRegion"],
        new Uri("Login"),
        new Uri("Target"));
}));
0 голосов
/ 16 мая 2011

Нет, это не плохая привычка. Это совершенно правильный сценарий. Прошло уже несколько лет с тех пор, как я перешел из Unity, но с самого начала вы должны явно указать на нужный конструктор и перечислить все параметры, а для примитивных выполните new ResolvedParameter("your value").

Также я заметил, что у вас есть параметр Type. Будьте осторожны с Unity, поскольку у него есть ... очень удивительный способ справиться с этим. У меня есть блог, подробно описывающий, что здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...