1

Я работаю над большим унаследованным приложением C#, и задача, назначенная мне, заключается в том, чтобы удалить все применения статического заводского класса ServiceLocator.GetObject<T>() и заменить на все вложенные зависимости конструктора.Требовать фабричный класс в методе расширения

По большей части это просто, однако в кодовой базе приложений есть около 50 случаев, где это немного сложно. Например, Servicelocator используется в статическом классе или методе расширения или даже в WPF MarkupExtension !.

Например, если бы вы столкнулись с фрагментом кода, как это, что бы вы сделали? (Кроме крика)

public static class MyExtensions 
{ 
    private static ISingletonServiceOne _ServiceOne = null; 
    private static ISingletonServiceTwo _ServiceTwo = null; // etc ... 

    public static SummaryHeader GetBannerSummary(this IModel rfq, object requester) 
    { 
     Guard.ArgumentNotNull(rfq, "rfq"); 
     Guard.ArgumentNotNull(requester, "requester"); 

     if (_ServiceOne == null) 
     { 
      _ServiceOne = ServiceLocator.GetService<ISingletonServiceOne>(requester); 
      Guard.ArgumentNotNull(_ServiceOne, "_ServiceOne"); 
     } 

     return _ServiceOne.GetBannerSummary(rfq); 
    } 

В приведенных выше методе ServiceLocator.GetObject() используется в качестве метода расширения на IModel, чтобы найти одноплодный зарегистрированный сервис и выполнить метод на этом, используя IModel.

Возникает вопрос:

  • Существуют ли какие-либо шаблоны/практики, чтобы избежать такого рода вещи - в DI контейнер, необходимый в статическом классе, стоимость преобразователя или метод расширения
  • Существуют ли какие-либо шаблоны/методы решения циклических зависимостей в DI?
  • Что бы вы сделали в вышеупомянутом задании, существует компромисс между хорошим кодом и временем доставки?

Я имею в виду, чтобы переместить GetBannerSummary() метод из расширений и только IModel в этом случае, однако (не смейтесь) бывают случаи одного и того же ServiceLocator используется в ValueConverters (WPF) и MarkupExtensions : 0

ваших комментариев/предложения оценило

ответ

2

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

Единственным (слегка) лучшим решением является перемещение вызова ServiceLocator в ленивое загруженное свойство, так что зависимость может быть введена во время модульного тестирования.

В вашем случае, однако, это не будет летать, поскольку у вас есть свойство requester, переданное в GetService, и в этом случае вам в идеале необходимо добавить зависимость IServiceOneFactory, с которой вы можете передать объект реквестера. Итак:

public interface IServiceOneFactory 
{ 
    ISingletonServiceOne Create(object requester); 
} 

public static class MyExtensions 
{ 
    public static IServiceOneFactory ServiceOneFactory 
    { 
     get 
     { 
      if(_ServiceOneFactory==null) 
       _ServiceOneFactory = ServiceLocator.GetService<IServiceOneFactory>(); 
      return _ServiceOneFactory; 
     } 
     set { _ServiceOneFactory = value; } 
    } 

    private static IServiceOneFactory _ServiceOneFactory = null; 
    private static ISingletonServiceOne _ServiceOne = null; 
    private static ISingletonServiceTwo _ServiceTwo = null; // etc ... 

    public static SummaryHeader GetBannerSummary(this IModel rfq, object requester) 
    { 
     Guard.ArgumentNotNull(rfq, "rfq"); 
     Guard.ArgumentNotNull(requester, "requester"); 

     if (_ServiceOne == null) 
     { 
      _ServiceOne = ServiceOneFactory.Create(requester); 
      Guard.ArgumentNotNull(_ServiceOne, "_ServiceOne"); 
     } 

     return _ServiceOne.GetBannerSummary(rfq); 
    } 
} 
+0

Привет, спасибо за ответ - я отредактировал Requestor, поскольку внутренне реализация ServiceLocator на самом деле ничего не делает с ним! Согласитесь с вашим прогнозом. Это довольно шокирующая паутина спагетти, с которой я имею дело, поэтому любые предложения по ее расторжению приветствуются:) –

+0

Привет, Андрей, приветствую - нам все пришлось пройти через это! Я думаю, что вы все делаете правильно, но я не вижу пути вокруг ServiceLocator в статике, расширениях и т. Д.Это необходимое зло, если вы сохранили все свои зависимости модульным, как и следовало ожидать. –

+0

Да, большой рефакторинг, как требование, потребовало повторного использования большого фрагмента кода в качестве призмы «Модуль» в другом проекте. Моя реакция, когда я услышал, что это «LOL». Во всяком случае, из 120 применений ServiceLocator у меня сократилось до 60. Я думаю, что я смогу больше обрезать, но некоторые могут остаться, если нет «простого решения». Большое спасибо –

2

ли возможность вводить IServiceX в классах вместо того, чтобы использовать статический класс аксессора? Возможно, сделать метод GetBannerSummary частью абстрактного базового класса, который реализует IModel?

DI не летает, когда вы не контролируете создание объекта. Триггеры, поведение или разметка-расширения в WPF попадают в эту категорию. Там нет возможности использовать ServiceLocator.

+0

Хмм, как я подозревал, watson ... Кажется, мне придется сделать очень много работы, чтобы распутать эти спагетти –

Смежные вопросы