Помогите разобраться с контекстной привязокой Ninject'а
От: alex303  
Дата: 25.10.16 14:32
Оценка:
В общем, ситуация такая:
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);
        }
    }
}
Отредактировано 25.10.2016 14:38 alex303 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.