Ответ 1
Итак, идеальный способ сделать это из того, что Я прочитал, вводя ядро когда вам нужно получить доступ к МОК... хорошо что все хорошо и хорошо; мы сохраняем использование SL до минимума.
Нет, инъекция ядра в ваши бизнес-классы - не лучший способ. Лучший способ - создать factory, например. IFooFactory { IFoo Create(); }
или Func<IFoo>
, и пусть это создаст новый экземпляр.
Реализация этого интерфейса переходит в составной корень, получает экземпляр ядра и разрешает использование ядра. Это позволяет вашим классам освобождаться от конкретного контейнера, и вы можете повторно использовать их в другом проекте с использованием другого контейнера. В случае Func вы можете использовать следующий модуль: Поддерживает ли Ninject Func (автоматически сгенерированный factory)? 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();
Возможно, вы хотите переключиться на конфигурацию контейнера на основе конвенции вместе с рефакторингом. В этом случае я добавлю атрибут для всех рефакторированных классов, чтобы пометить их и удалить их после завершения рефакторинга. В соглашениях вы можете использовать этот атрибут для фильтрации для всех реорганизованных классов.