Ninject Contextual binding

时间:2011-03-10 02:02:07

标签: .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");

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

2 个答案:

答案 0 :(得分: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 );
    }
}

上述方法(尝试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 );
    }

请注意,这通常不是一个好主意,但同样,一个更好的问题会让你在那里得到更好的语境答案......

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

编辑:请注意https://github.com/ninject/ninject/wiki/Contextual-Binding自此问题(和答案)以来已经有了重大更新

答案 1 :(得分:6)

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

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

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

    public interface ISystemClock
    {
        DateTime Now { get; }
    }
    

    您可以注入此类服务。

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

    public interface IMyAppsConfiguration
    {
        double Value1 { get; }
        double Value2 { get; }
        double Value3 { get; }
    }
    
  3. 使用Ninject直接注册课程。

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