Я решил начать использовать Ninject и сталкиваться с проблемой. Скажите, что у меня есть следующий сценарий. Я имею IService
взаимодействуйте через интерфейс и 2 класса, реализовывая этот интерфейс. И также у меня есть класс, который имеет конструктора, получающего IService и интервал. Как я могу создать экземпляр этого класса с Ninject (я не хочу соединять этот интервал проводами, я хочу передать его каждый раз, когда я получаю экземпляр)?
Вот некоторый код, иллюстрирующий ситуацию:
interface IService
{
void Func();
}
class StandardService : IService
{
public void Func()
{
Console.WriteLine("Standard");
}
}
class AlternativeService : IService
{
public void Func()
{
Console.WriteLine("Alternative");
}
}
class MyClass
{
public MyClass(IService service, int i)
{
this.service = service;
}
public void Func()
{
service.Func();
}
IService service = null;
}
class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(new InlineModule(
x => x.Bind<IService>().To<AlternativeService>(),
x => x.Bind<MyClass>().ToSelf()));
IService service = kernel.Get<IService>();
MyClass m = kernel.Get<MyClass>();
m.Func();
}
}
Для этой цели в 1.0 существовал аргумент With.ConstructorArgument
. В версии 2.0 синтаксис немного изменился: -
With.Parameters.ConstructorArgument с ninject 2.0
См. Внедрение значения в внедренную зависимость для получения дополнительных сведений и примеров использования контекст, поставщики и аргументы для более правильной передачи подобных вещей.
РЕДАКТИРОВАТЬ: Поскольку Стивен решил притвориться, что мой комментарий не имеет отношения к делу, я лучше проясню то, что я говорю, с помощью нескольких примеров (для 2.0):
MyClass m = kernel.Get<MyClass>( new ConstructorArgument( "i", 2) );
который, на мой взгляд, очень ясен и точно описывает, что происходит.
Если вы находитесь в положении, когда вы можете определить параметр более глобальным способом, вы можете зарегистрировать поставщика и сделать это следующим образом:
class MyClassProvider : SimpleProvider<MyClass>
{
protected override MyClass CreateInstance( IContext context )
{
return new MyClass( context.Kernel.Get<IService>(), CalculateINow() );
}
}
И зарегистрировать его так:
x => x.Bind<MyClass>().ToProvider( new MyClassProvider() )
NB CalculateINow ()
бит - это то место, где вы должны вставить свою логику, как в первом ответе.
Или сделайте его более сложным, например:
class MyClassProviderCustom : SimpleProvider<MyClass>
{
readonly Func<int> _calculateINow;
public MyClassProviderCustom( Func<int> calculateINow )
{
_calculateINow = calculateINow;
}
protected override MyClass CreateInstance( IContext context )
{
return new MyClass( context.Kernel.Get<IService>(), _calculateINow() );
}
}
Что вы должны зарегистрировать так:
x => x.Bind<MyClass>().ToProvider( new MyClassProviderCustom( ( ) => new Random( ).Next( 9 ) ) )
ОБНОВЛЕНИЕ: Новые механизмы, которые демонстрируют значительно улучшенные шаблоны с меньшим количеством шаблонов, чем приведенные выше, воплощены в Ninject.Extensions .Factory
, см .:
https://github.com/ninject/ninject.extensions.factory/wiki
Как было сказано ранее, , если вам нужно передать каждый раз с разными параметрами и у вас есть несколько уровней в графике зависимостей, вам может потребоваться сделать что-то вроде этого .
Последнее соображение заключается в том, что, поскольку вы не указали с помощью
, по умолчанию будет использоваться значение по умолчанию, как указано / по умолчанию в параметрах ядра ( TransientBehavior
в примере), который может отображать тот факт, что фабрика вычисляет i
на ходу [например, если объект был кэширован]
Теперь, чтобы прояснить некоторые другие моменты в комментариях, которые быть FUDed и замалчивается. Некоторые важные моменты, которые следует учитывать при использовании DI, будь то Ninject или что-то еще:
Сделайте как можно больше с помощью внедрения конструктора, чтобы вам не нужно было использовать специфические для контейнера атрибуты и уловки.В блоге есть хорошая запись под названием Ваш контейнер IoC показывает .
Сведите к минимуму код, идущий к контейнеру и запрашивающий материалы - в противном случае ваш код будет связан с а) конкретным контейнером (который CSL может минимизировать) б) способом, которым построен весь ваш проект. Об этом есть хорошие сообщения в блогах, показывающие, что CSL не делает то, что вы думаете. Эта общая тема называется Размещение службы и внедрение зависимостей . ОБНОВЛЕНИЕ: см. http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx для подробного и полного обоснования.
Минимизируйте использование статики и синглтонов
Не предполагайте, что существует только один [глобальный] контейнер, и что это нормально - просто запрашивать его всякий раз, когда он вам нужен, как хорошая глобальная переменная. Правильное использование нескольких модулей и Bind.ToProvider ()
дает вам структуру для управления этим. Таким образом, каждая отдельная подсистема может работать сама по себе, и у вас не будет компонентов нижнего уровня, привязанных к компонентам верхнего уровня и т. Д.
Если кто-то хочет заполнить ссылки на блоги, о которых я говорю, я ' Я ценю это (все они уже связаны из других сообщений на SO, так что все это просто дублирование, введенное пользовательским интерфейсом с целью избежать путаницы с вводящим в заблуждение ответом.)
Итак, если бы только Джоэл мог войти и действительно объяснить мне, какой хороший синтаксис и / или правильный способ сделать это!
ОБНОВЛЕНИЕ: хотя этот ответ явно полезен по количеству набранных голосов, я хотел бы сделать следующие рекомендации: