Ninject Контекстная привязка - PullRequest
2 голосов
/ 10 марта 2011

Я в основном использую основные функции Ninject.Поэтому этот вопрос может быть слишком очевидным.Если так, пожалуйста, извините.В любом случае, у меня есть следующее в модуле:

Bind<Double>().ToConstant(TimeSpan.FromSeconds(10).TotalMilliseconds).Only(When.Context.Target.Name.AsString=="A");
Bind<Double>().ToConstant(TimeSpan.FromHours(1).TotalMilliseconds).Only(When.Context.Target.Name.AsString=="B");
Bind<Double>().ToConstant(TimeSpan.FromMinutes(5).TotalMilliseconds).Only(When.Context.Target.Name.AsString=="C");

Теперь вопрос заключается в том, как я могу использовать kernel.get<Double>() для разрешения любой из указанных выше привязок, которые мне нужны?

Ответы [ 2 ]

9 голосов
/ 10 марта 2011

Во-первых, можем ли мы сохранить привязку на основе соглашений к значению https://github.com/ninject/ninject.extensions.conventions, пожалуйста (в отличие от явных привязок, как вы делаете в вашем примере) - я отредактировал заголовок вопроса, чтобы отразить это.

Теперь, чтобы ответить на ваш актуальный вопрос. Похоже, вы хотите установить контекстные привязки, чтобы иметь возможность вводить соответствующие значения в разных контекстах. Я бы посоветовал, чтобы редактирование в лучшем примере того, чего вы на самом деле пытаетесь достичь, могло бы дать вам лучший ответ.

Первая проблема заключается в том, что вы используете синтаксис v1. Вот пример того, чего вы пытаетесь достичь в синтаксисе v2:

class ContextualBindingsExample
{
    internal class A
    {
        public A( double x )
        {
            X = x;
        }

        public double X { get; private set; }
    }

    internal class B
    {
        public B( double y )
        {
            Y = y;
        }

        public double Y { get; private set; }
    }

    [Fact]
    public static ContextualBindingAllowsOneToFilterWhenInjectingIntoRoots()
    {
        var k = new StandardKernel();
        k.Bind<double>().ToConstant( 1 ).WhenInjectedInto<A>();
        k.Bind<double>().ToConstant( 2 ).When( request => request.Target.Name == "y" );
        Assert.Equal( k.Get<B>().Y, 2 );
        Assert.Equal( k.Get<A>().X, 1 );
    }
}

Вышеупомянутый подход (попытка Get что-то, что соответствует вашей условной ситуации), как правило, вам нужен. Если нет, вы можете синтезировать его следующим образом. NB. Это ненормально, и вы, вероятно, делаете что-то не так, если хотите это сделать.

То, что вы также можете искать, - это способ спрятать вещи в контейнере, а затем извлечь их в соответствии с критериями фильтрации. Это выглядит так:

    [Fact]
    public static void BindingMetadataShouldAllowContextualFiltering()
    {
        var k = new StandardKernel();
        k.Bind<double>().ToConstant( 2 ).WithMetadata( "a", "b" );
        k.Bind<double>().ToConstant( 30 ).WithMetadata( "b", 2 );
        Assert.Equal( k.Get<double>( metadata => metadata.Get<string>( "a" ) == "b" ), 2 );
        Assert.Equal( k.Get<double>( metadata => metadata.Get<int>( "b" ) == 2 ), 30 );
    }

Обратите внимание, что это, как правило, не очень хорошая идея, но, опять же, лучший вопрос поможет вам получить более контекстный ответ ...

Теперь я рекомендую прочитать здесь самые популярные ответы @Mark Seemann, чтобы получить ключевые принципы, чтобы вы не попали в сорняки, пытаясь снова разобраться в хитрости низкоуровневого инструмента DI!

РЕДАКТИРОВАТЬ: Обратите внимание, что https://github.com/ninject/ninject/wiki/Contextual-Binding был значительно обновлен с момента написания этого вопроса (и ответа)

6 голосов
/ 10 марта 2011

Хотя такая конфигурация может работать, она особенно хрупкая и приведет к сложному пониманию кода и сложной конфигурации DI.Соглашение о конфигурации хорошо, но не пытайтесь внедрять что-либо кроме сервисов.double не является службой, это значение.

Вот три других подхода, которые вы можете рассмотреть:

  1. Определите одну или несколько служб с четкими именамикоторые знают, как вернуть эти значения.Например:

    public interface ISystemClock
    {
        DateTime Now { get; }
    }
    

    Вы можете внедрить такую ​​услугу.

  2. Определить интерфейс для конфигурации приложения:

    public interface IMyAppsConfiguration
    {
        double Value1 { get; }
        double Value2 { get; }
        double Value3 { get; }
    }
    
  3. Зарегистрируйте классы напрямую, используя Ninject.

Какой лучший ответ трудно сказать, потому что ваш вопрос мало раскрывает то, что вы на самом деле пытаетесь внедрить.Вы пытаетесь ввести двойные числа, но что на самом деле представляют эти двойные числа?

...