Итак, идеальный способ сделать это из того, что я прочитал, - внедрить ядро всякий раз, когда вам нужен доступ к IOC ... ну, это все хорошо и хорошо;мы ограничиваем использование SL до минимума.
Нет, внедрение ядра в ваши бизнес-классы - не лучший способ.Лучший способ - создать фабрику, например IFooFactory { IFoo Create(); }
или Func<IFoo>
, и позволить этому создать новый экземпляр.
Реализация этого интерфейса входит в составной корень, получает экземпляр ядра и выполняетрешение с использованием ядра.Это освобождает ваши классы от конкретного контейнера, и вы можете использовать их в другом проекте, используя другой контейнер.В случае Func вы можете использовать следующий модуль: Поддерживает ли Ninject Func (автоматически сгенерированная фабрика)? Ninject 2.4 будет иметь встроенную поддержку для этого.
Что касается рефакторингаидет, вряд ли можно сказать вам, каков наилучший путь, не зная исходного кода вашего приложения.Я могу просто дать вам подход, который, вероятно, может сработать.
Полагаю, вы хотите в течение длительного времени перестроить все приложение в надлежащий DI.То, что я делал однажды для довольно большого проекта (30-40 человеко-лет), было примерно следующим:
Начните с составного корня (-ов) и перейдите вниз по дереву объектов и измените один класс за другим наиспользуйте правильный DI.Как только вы достигли всех листов, начните проводить рефакторинг всех сервисов, которые не зависят от других сервисов и работают на их листах, используя тот же подход.После этого продолжайте работу с сервисами, которые зависят только от сервисов, которые уже были реорганизованы, и повторяйте их, пока все сервисы не будут реорганизованы.Все эти шаги можно выполнять один за другим, чтобы постоянно улучшать код, в то же время добавляя новые функции.В то же время ServiceLocation является приемлемым, если основное внимание уделяется правильной настройке как можно скорее.
Пример псевдокода:
Foo{ ServiceLocator.Get<Service1>(), new Bar() }
Bar{ ServiceLocator.Get<IService1>(), ServiceLocator.Get<IService2>(), new Baz() }
Baz{ ServiceLocator.Get<IService3>() }
Service1 { ServiceLocator.Get<Service3>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { new SomeClass()}
Шаг 1 - Изменить корень (Foo)
Foo{ ctor(IService1, IBar) }
Bar{ ServiceLocator.Get<IService1>(), ServiceLocator.Get<IService2>(), new Baz() }
Baz{ ServiceLocator.Get<IService3>() }
Service1 { ServiceLocator.Get<IService2>() }
Service2 { ServiceLocator.Get<IService3>() }
Service3 { new SomeClass()}
Bind<IBar>().To<Bar>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Шаг 2 - Измените зависимости root
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ServiceLocator.Get<IService3>() }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { new SomeClass()}
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().ToMethod(ctx => ServiceLocator.Get<IService2>());
Шаг 3 - Измените их зависимости и продолжайте до тех пор, пока не окажетесь у листьев
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { new SomeClass() }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().ToMethod(ctx => ServiceLocator.Get<IService2>());
Bind<IService3>().ToMethod(ctx => ServiceLocator.Get<IService3>());
Шаг 4- Рефакторинг сервисов, которые не зависят от других
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { ctor(ISomeClass) }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<ISomeClass>().To<SomeClass>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().ToMethod(ctx => ServiceLocator.Get<IService2>());
Bind<IService3>().To<Service3>().InSingletonScope();
Шаг 5 - Следующий рефакторинг тех, которые зависят от сервисов, которые имеют только рефакторированные сервисы в качестве зависимости.
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ctor(IService3) }
Service3 { ctor(ISomeClass) }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<ISomeClass>().To<SomeClass>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().To<Service2>().InSingletonScope();
Bind<IService3>().To<Service3>().InSingletonScope();
Шаг 6 -Повторяйте до тех пор, пока все службы не будут подвергнуты рефакторингу.
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ctor(IService2) }
Service2 { ctor(IService3) }
Service3 { ctor(ISomeClass) }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<ISomeClass>().To<SomeClass>();
Bind<IService1>().To<Service1>().InSingletonScope();
Bind<IService2>().To<Service2>().InSingletonScope();
Bind<IService3>().To<Service3>().InSingletonScope();
Возможно, вы хотите переключиться на конфигурацию контейнера на основе соглашения вместе с рефакторингом.В этом случае я бы добавил атрибут ко всем классам рефакторинга, чтобы пометить их, и удалил его снова после того, как весь рефакторинг завершен.В соглашениях вы можете использовать этот атрибут, чтобы отфильтровать все реорганизованные классы.