2011-03-10 75 views
2

我主要使用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>()解析到,我想上面的绑定中的任何一个?

+0

参见http://stackoverflow.com/questions/2507881/contextual-bindings-with-ninject-2-0 – 2011-03-10 14:10:17

回答

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已显著更新,因为这个问题(和答案),其中书面

+0

非常感谢。你不仅给出了关于设计的非常有建设性的暗示,而且还回答了我的实际问题。我认为,即使这不是一个有用的选择,至少如果有人想以正确的方式使用它,他们会发现你的例子有用。对此,我真的非常感激!关于基于分流的绑定我正在反思我从ninject wiki中读到的内容https://github.com/ninject/ninject/wiki/Conventions-Based-Binding虽然可能我误解了。 – amirmonshi 2011-03-10 13:57:26

+1

@amirmonshi:谢谢你的答复和跟进。现在你已经指出了这一点,难怪你会称之为基于约定的绑定。文章将很快收到一些工作 - 正如它所指出的那样,它有点困惑 - 对于我来说,有一些约定(通常是基于名称的CoC la Ruby)与上下文相关(即具有属性和其他更丰富的上下文,关注静态信息)。我认为其他一些文章涵盖了上下文绑定。希望我能尽快解决,我可以消除一些混乱。 – 2011-03-10 14:08:06

+0

@amirmonshi:我也编辑了一些对条件绑定的引用,并用Contextual取代。这就是我用术语来玩的快速和松散。并且不要忘记关注我发布在 – 2011-03-10 14:14:02

6

虽然这样的配置可能会起作用,但它特别脆弱,会导致难以理解的代码和难以理解的DI配置。约定优于配置是好的,但不要尝试注入其他任何东西而不是服务。 A double不是服务,而是价值。

以下是你可能要考虑其他三个方法:

  1. 定义一个或多个服务与懂得回报这些价值观明确的名称。例如:

    public interface ISystemClock 
    { 
        DateTime Now { get; } 
    } 
    

    您可以注入此类服务。

  2. 定义一个接口,用于应用程序的配置:

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

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

+0

+1为好的提示:) – amirmonshi 2011-03-10 13:58:59

+0

重新格式化后,我能够读取它,这很好 - 我同意你的OP的具体示例中心点不是一个好主意+1! – 2011-03-10 16:44:37

+0

@Ruben:感谢+,并感谢重新格式化。我不知道如何将代码包含在列表项中。现在我看到了4个额外的空间。你已经有我的+,所以我不能给你更多;-) – Steven 2011-03-10 18:19:44