Ninject Contextual binding

ami*_*shi 2 .net dependency-injection ninject

我大多使用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");
Run Code Online (Sandbox Code Playgroud)

现在,问题是我如何使用kernel.get<Double>()解析我想要的上述任何一个绑定?

Rub*_*ink 9

首先,我们可以保持基于约定的绑定意味着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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

上述方法(尝试Get与您的条件情况相匹配的东西)通常是您所需要的.如果没有,您可以按如下方式合成它.注意这不是一件普通的事情,如果你想这样做,你可能会做错事.

您可能正在寻找的是一种将容器存放在容器中然后根据过滤条件将其拉出的方法.这是这样的:

    [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 );
    }
Run Code Online (Sandbox Code Playgroud)

请注意,这通常不是一个好主意,但同样,一个更好的问题将为您提供更好的更多情境答案......

现在,我建议在这里阅读@Mark Seemann最受欢迎的答案,以获得关键原则,这样你就不会在杂草中试图理解这样的低级DI工具!

编辑:请注意https://github.com/ninject/ninject/wiki/Contextual-Binding已经显着更新,因为这个问题(和答案)写的地方


Ste*_*ven 6

虽然这样的配置可能有效,但它特别脆弱,并且会导致难以理解的代码和难以理解的DI配置.约定优于配置,但不要尝试注入除服务以外的任何东西.A double不是服务,而是价值.

以下是您可能需要考虑的其他三种方法:

  1. 使用明确的名称定义一个或多个服务,这些名称知道如何返回这些值.例如:

    public interface ISystemClock
    {
        DateTime Now { get; }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    你可以注入这样的服务.

  2. 为应用程序的配置定义接口:

    public interface IMyAppsConfiguration
    {
        double Value1 { get; }
        double Value2 { get; }
        double Value3 { get; }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用Ninject直接注册类.

什么是最好的答案很难说,因为你的问题没有透露你实际上要注入的内容.你试图注入双打,但这些双打实际上代表了什么?