Ninject默认语境结合 [英] Ninject default contextual binding

查看:135
本文介绍了Ninject默认语境结合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些不同的具体实现的接口。我想给Ninject默认使用且仅当名称匹配使用其他实现。 。比如,我有以下的绑定

 绑定< ISomething>()为<。DefaultSomething>()
绑定&所述; ISomething方式>()到< OtherSomething方式>()命名(55abd8b8-097f-4e1c-8d32-95cc​​97910604);



我想是,如果命名节不匹配,使用DefaultSomething实现。当我通过在明确的约束GUID,它工作正常。当我通过任何其他GUID我得到了无匹配的绑定可用异常

 绑定< ISomething>()。到< OtherSomething方式>()命名(55abd8b8-097f-4e1c-8d32-95cc​​97910604); 
绑定&所述; ISomething方式>()到< DefaultSomething>()

绑定&所述; ISomething方式>()到< DefaultSomething>()
绑定&所述; ISomething方式>()至< ; OtherSomething方式>()时(CTX = GT; ctx.Service =空&放大器;!&放大器; ctx.Service.Name ==55abd8b8-097f-4e1c-8d32-95cc​​97910604);



我使用。当检查还试图绑定,我试图扭转的顺序如下图所示然而,我从来没有能够绑定,除非我通过在被明确指定的GUID。



This文章似乎表明,默认绑定工作,所以我必须做一些错误的。 ?任何建议






编辑:这是显示我试图解决这个问题一个完整的例子。期望的行为是 kernel.Get< i编号方式>(三公)写()返回未知号码

 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;
使用Ninject;

命名空间NinjectTest
{
接口i编号
{
串写();
}

类UnknownNumber:i编号
{
公共字符串写入()
{
返回未知号码;
}
}

类中的一个:i编号
{
公共字符串写入()
{
返回1 =一
}
}

类两种:i编号
{
公共字符串写入()
{
返回2 = 2
}
}

类节目
{
静态无效的主要(字串[] args)
{
StandardKernel内核=新StandardKernel();
kernel.Bind&所述; i编号方式>()到< UnknownNumber>();
kernel.Bind< i编号方式>()为<一种方式>()命名(1);
kernel.Bind< i编号方式>()到<二方式>()命名(二);

Console.WriteLine(kernel.Get< i编号>(1)写());
Console.WriteLine(kernel.Get< i编号>(二),写());
Console.WriteLine(kernel.Get< i编号>(三公)写());

到Console.ReadLine();
}
}
}


解决方案

您完全missunderstood命名的绑定:



给人一种绑定的名称不是一个条件。没有约束,要求他们时,你仍然会得到所有的人。添加一个名称更改对自己绝对没有



请求使用一个名称的一个实例添加了约束:




只有绑定的名字相匹配的给定的一个应退还




在你的情况,你给我一个实例其绑定的名称是三化。你希望它返回 UnknownNumber ,它甚至没有一个名字。



这可以通过<实现STRONG>或者




  1. 传递参数和添加条件的检查,如果参数匹配,或绑定

  2. 通过适合的名称或命名的实体并声明未命名的隐式。


$ b约束$ b

选项1:

 公共类CustomerIdParameter:参数
{
公共CustomerIdParameter(串ID):基地(客户编号(对象)空,假)
{
this.Id = ID;
}
公共字符串ID {搞定;私人集; }
}

kernel.Bind< ISomething>()到<&默认GT;();
kernel.Bind&所述; ISomething方式>()向<其它>()
。当(R => r.Parameters.OfType&下; C​​ustomerIdParameter>()
。单()的标识。 ==SomeName);

kernel.Get< IWeapon>(新CustomerIdParameter(SomeName))ShouldBeInstanceOf<剑与GT;();



我把它留给你写的扩展方法做出的定义和解决更容易。



选项2:

 绑定< ISomething>()为<默认过夜。 ()Binding.IsImplicit = TRUE。 
绑定< ISomething方式>()为<其他方式>()命名(SomeName)

公共静态牛逼GetNamedOrDefault< T>(此的iKernel内核,字符串名称)
{
返回kernel.Get< T>(M = GT; m.Name == NULL || m.Name ==名);
}



不过说实话,我认为你想做的事似乎并没有成为一个什么恰当的设计:




  1. 保持绝对最低内核的访问。你在做什么这里是一个的ServiceLocator类 Ninject的使用。

  2. 如果没有绑定可预期的情况下,我宁愿期待一个例外比使用默认实例,因为这是一个错误。


I have an interface with a few different concrete implementations. I am trying to give Ninject a default to use and only use the other implementation if a name matches. For instance, I have the following bindings.

Bind<ISomething>().To<DefaultSomething>()
Bind<ISomething>().To<OtherSomething>().Named("55abd8b8-097f-4e1c-8d32-95cc97910604");

What I would like is if the Named section doesn't match, to use the DefaultSomething implementation. When I pass in the explicitly bound guid, it works fine. When I pass in any other guid I get the "No matching bindings are available" exception.

Bind<ISomething>().To<OtherSomething>().Named("55abd8b8-097f-4e1c-8d32-95cc97910604");
Bind<ISomething>().To<DefaultSomething>()

Bind<ISomething>().To<DefaultSomething>()
Bind<ISomething>().To<OtherSomething>().When(ctx => ctx.Service != null && ctx.Service.Name == "55abd8b8-097f-4e1c-8d32-95cc97910604");

I have also tried using .When to check the binding and I have tried reversing the order like below however I am never able to bind unless I pass in the Guid that is explicitly named.

This article seems to indicate that default bindings work, so I must be doing something wrong. Any suggestions?


Edit: Here is a complete example showing the problem I am trying to solve. The desired behavior is for kernel.Get<INumber>("Three").Write() to return "Unknown Number"

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject;

namespace NinjectTest
{
    interface INumber
    {
        string Write();
    }

    class UnknownNumber : INumber
    {
        public string Write()
        {
            return "Unknown Number";
        }
    }

    class One : INumber
    {
        public string Write()
        {
            return "1 = One";
        }
    }

    class Two : INumber
    {
        public string Write()
        {
            return "2 = Two";
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            StandardKernel kernel = new StandardKernel();
            kernel.Bind<INumber>().To<UnknownNumber>();
            kernel.Bind<INumber>().To<One>().Named("One");
            kernel.Bind<INumber>().To<Two>().Named("Two");

            Console.WriteLine(kernel.Get<INumber>("One").Write());
            Console.WriteLine(kernel.Get<INumber>("Two").Write());
            Console.WriteLine(kernel.Get<INumber>("Three").Write());

            Console.ReadLine();
        }
    }
}

解决方案

You completely missunderstood named bindings:

Giving a binding a name is NOT a condition. You will still get all of them when requesting them without a constraint. Adding a name changes absolutely nothing on its own.

Requesting an instance using a name adds the constraint:

only bindings whose name matches the given one shall be returned

In your case, you gave me an instance whose binding's name is "three". And you expect it to return UnknownNumber, which does not even have a name.

This can be achieved by either

  1. passing a parameter and adding conditions to the bindings that check if the parameter matches, or
  2. passing a constraint that fits the name or the unnamed instance and declare the unnamed one implicit.

Option 1:

public class CustomerIdParameter : Parameter
{
    public CustomerIdParameter(string id) : base("CustomerId", (object)null, false)
    {
        this.Id = id;
    }
    public string Id { get; private set; }
}

kernel.Bind<ISomething>().To<Default>();
kernel.Bind<ISomething>().To<Other>()
      .When(r => r.Parameters.OfType<CustomerIdParameter>()
                             .Single().Id == "SomeName");

kernel.Get<IWeapon>(new CustomerIdParameter("SomeName")).ShouldBeInstanceOf<Sword>();

I leave it up to you to write the extension methods to make the definition and resolve easier.

Option 2:

Bind<ISomething>().To<Default>().Binding.IsImplicit = true;
Bind<ISomething>().To<Other>().Named("SomeName")

public static T GetNamedOrDefault<T>(this IKernel kernel, string name)
{
    return kernel.Get<T>(m => m.Name == null || m.Name == name);
}

But honestly I think what you want to do doesn't seem to be a proper design:

  1. Keep your access to the kernel to an absolute minimum. What you're doing here is a ServiceLocator-like usage of Ninject.
  2. If no binding is available for an expected instance, I'd rather expect an exception than using a default instance because this is a bug.

这篇关于Ninject默认语境结合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆