В общем, ситуация такая:
1.Ninject
2. Есть некоторое количество условных "сервисов" (Service1) которые статически биндятся и используюся в некоторых классах (Foo, Bar)
но есть особый случай, когда "сервисы" должны при резолве "особого" класса использовать "особый" биндинг.
Особенность в том, что в конструктор "сервиса" должен попадать динамический параметр прям из рантайма.
Я понимаю, что звучит мутно, так что полный тестовый код далее.
конкретно вопрос про вот это место:
// .ToSelf() - все работает как ожидается в обоих случаях (common и special)
// Foo получит Service1 для common, и SpecialService1 для special
//kernel.Bind<Foo>().ToSelf();
// .ToMethod() - работает, но не так как хочется
// Foo всегда получит Service1 (Get<Service1>). Как тут узнать что изначально делается Get с именем "special_case" и Service1 должен резолвится как SpecialService1?
kernel.Bind<Foo>().ToMethod(context => new Foo(context.Kernel.Get<Service1>()));
Вопрос в комментарии. Почему ручной вызов context.Kernel.Get<Service1>() вернет Service1, а не SpecialService1?
И как в ToMethod таки получить SpecialService1?
using System.Diagnostics;
using System.Linq;
using Ninject;
using Ninject.Parameters;
namespace NinjectMultipleBindings
{
//common
public class Service1
{
}
public class Foo
{
public Foo(Service1 service1)
{
Service1 = service1;
}
public Service1 Service1 { get; private set; }
}
public class Bar
{
public Bar(Service1 service1, Foo foo)
{
Service1 = service1;
Foo = foo;
}
public Service1 Service1 { get; private set; }
public Foo Foo { get; private set; }
}
// special
public class SpecialService1 : Service1
{
public SpecialService1(string param)
{
Param = param;
}
public string Param { get; private set; }
}
public class SpecialBar : Bar
{
public SpecialBar(Service1 service1, Foo foo)
: base(service1, foo)
{
}
}
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
// common
kernel.Bind<Service1>().ToSelf();
// .ToSelf() - все работает как ожидается в обоих случаях (common и special)
// Foo получит Service1 для common, и SpecialService1 для special
//kernel.Bind<Foo>().ToSelf();
// .ToMethod() - работает, но не так как хочется
// Foo всегда получит Service1 (Get<Service1>). Как тут узнать что изначально делается Get с именем "special_case" и Service1 должен резолвится как SpecialService1
kernel.Bind<Foo>().ToMethod(context => new Foo(context.Kernel.Get<Service1>()));
kernel.Bind<Bar>().ToSelf();
// special
kernel.Bind<Service1>().To<SpecialService1>().WhenAnyAncestorNamed("special_case").WithConstructorArgument("param", context => context.Parameters.First(x => x.Name == "param"));
kernel.Bind<SpecialBar>().ToSelf().Named("special_case");
// common
var bar1 = kernel.Get<Bar>();
Debug.Assert(typeof(Bar) == bar1.GetType());
Debug.Assert(typeof(Service1) == bar1.Service1.GetType());
Debug.Assert(typeof(Foo) == bar1.Foo.GetType());
Debug.Assert(typeof(Service1) == bar1.Foo.Service1.GetType());
// special
var bar2 = kernel.Get<SpecialBar>(new ConstructorArgument("param", "testval", true));
Debug.Assert(typeof(SpecialBar) == bar2.GetType());
Debug.Assert(typeof(SpecialService1) == bar2.Service1.GetType());
Debug.Assert("testval" == ((SpecialService1)bar2.Service1).Param);
Debug.Assert(typeof(Foo) == bar2.Foo.GetType());
Debug.Assert(typeof(SpecialService1) == bar2.Foo.Service1.GetType()); // !!! Тут упадет, если .ToMethod() используется
Debug.Assert("testval" == ((SpecialService1)bar2.Foo.Service1).Param);
}
}
}