【问题标题】:Ninject Contextual bindingNinject 上下文绑定
【发布时间】:2011-03-10 02:02:07
【问题描述】:

我大部分时间都在使用 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&lt;Double&gt;() 来解析我想要的上述任何一种绑定?

【问题讨论】:

标签: .net dependency-injection ninject


【解决方案1】:

首先,我们能否将基于约定的绑定保留为 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 自从写下这个问题(和答案)以来已经显着更新

【讨论】:

  • 非常感谢。您不仅对设计提供了非常有建设性的提示,而且还回答了我的实际问题。我认为即使这不是一个有用的选择,至少如果有些人想以正确的方式使用它,他们会发现您的示例很有用。对此,我真的非常感激!关于基于约定的绑定我反映了我从 ninject wiki 阅读的内容 github.com/ninject/ninject/wiki/Conventions-Based-Binding 可能我误解了。
  • @amirmonshi:感谢您的确认和跟进。既然您指出了这一点,难怪您将其称为基于约定的绑定。这篇文章很快就会收到一些工作 - 正如它所指出的那样,它有点困惑 - 对我来说,有约定(通常是 CoC a la ruby​​,基于名称)与上下文(即,具有属性和其他更丰富的上下文,重点是静态信息) )。我认为其他一些文章涵盖了上下文绑定。希望我能尽快解决这个问题,我可以消除一些困惑。
  • @amirmonshi:我还编辑了一些对条件绑定的引用并替换为上下文。那是我在术语上玩得又快又松。并且不要忘记关注我在问题上发布的seealso
【解决方案2】:

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

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

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

    public interface ISystemClock
    {
        DateTime Now { get; }
    }
    

    你可以注入这样的服务。

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

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

什么是最好的答案很难说,因为您的问题并没有透露太多关于您实际尝试注入的内容。您正在尝试注入双打,但这些双打实际上代表什么?

【讨论】:

  • 在重新格式化后,我能够阅读它,这很好 - 我同意你关于 OP 的具体示例不是一个好主意 +1 的中心点!
  • @Ruben:感谢 + 并感谢重新格式化。我不知道如何在列表项中包含代码。现在我看到 4 个额外的空格可以解决问题。你已经有了我的+,所以我不能给你更多;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-23
相关资源
最近更新 更多