开发者

Ninject 2.0 - binding to a object that uses the same interface more than once?

Consider the following:

    public Something(IInterface concreteObjectOne, IInterface concreteObjectTwo) 
    {
        this.concreteObjectOne = concreteObjectOne;
        this.concreteObjectTwo = concreteObje开发者_如何学运维ctTwo;
    }

How do I set set this type of binding up with Ninject? I'd try Googling the term, but as I'm not sure what this is called I can't, nor can I find anything on the Wiki about this.

Edit:

I believe this is called Convention Based Binding, as described here. However this documentation is for version 1.0 and 2.0 does not have the Only method. I'd like this to be achieved without attributes - using the convention of names or something similiar.


In addition to the use of "Only" method, the article suggests another solution by specifying different attributes for the injected objects.

Example:

public class ObjectOneAttribute : Attribute
{

}  
public class ObjectTwoAttribute : Attribute
{

}

Then

public Something([ObjectOneAttribute] IInterface concreteObjectOne, [ObjectTwoAttribute] IInterface concreteObjectTwo) 
    {
        this.concreteObjectOne = concreteObjectOne;
        this.concreteObjectTwo = concreteObjectTwo;
    }

And when you want to bind the interface to the correct concrete object, use the "WhereTargetHas" method:

Bind<IInterface>().To<YourConcreteTypeOne>().WhereTargetHas<ObjectOneAttribute>();
Bind<IInterface>().To<YourConcreteTypeTwo>().WhereTargetHas<ObjectTwoAttribute>();

Update: Solution without using attributes:
Use the method "When":

Bind<IInterface>().To<YourConcreteTypeOne>().When(r => r.Target.Name == "concreteObjectOne");  
Bind<IInterface>().To<YourConcreteTypeTwo>().When(r => r.Target.Name == "concreteObjectTwo")

;


If I may be allowed to offer some general, instead of Ninject-specific, guidance on this, I would suggest that you reconsider your design slightly. The current constructor is vague because it offers no guidance about which implementation of IInterface that goes where - I realize that this is just a mock-up of your real API, and while the real API may offer more help to the human developer in the form of aptly named parameters, a machine like a DI Container cannot infer correct usage.

Many DI Containers offer some way to address such vagueness, for example by providing attributes you can use to associate names (metadata) with each dependency. AFAIR, Ninject has Inject attributes...

However, consider a couple of alternatives:

The first alternative is to encapsulate the two similar interface instances in an Parameter Object, like this:

public interface IParameterObject
{
    IInterface ObjectOne { get; }

    IInterface ObjectTwo { get; }
}

You can now change the constructor to take an instance of IParameterObject instead of the two interface instances themselves.

public Something(IParameterObject po)
{
    this.concreteObjectOne = po.ObjectOne;
    this.concreteObjectTwo = po.ObjectTwo;
}

This means that you can push configuration of IParameterObject to the Composition Root.

Another alternative to ponder is whether it makes sense to consider the case with two instances as just a special case of a more general design that takes any number of instances. This may not always be the case, but if it is, you can change the constructor to this:

public Something(IEnumerable<IInterface> objects)

I would personally prefer any of the above suggestions over anything that uses specific Ninject features, because it forces me to make the API more explicit in general, and thus more readable and maintainable.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜