简体   繁体   中英

C# Ninject Parameter based Binding

I am using Ninject to inject dependencies. I have the following class structure :

public interface IClass
{
}

public class Class: IClass
{
 public virtual void Method(Object context)
 {
  --------
 }
}   

public class Class1: IClass
{
 public override void Method(Object context)
 {
  --------
 }
}

public class Class2: IClass
{
 public override void Method(Object context)
 {
  --------
 }
}

context contains - HasBilling , HasPayment properties along with other more properties.

Method() is invoked by using factory pattern:

public interface IClassFactory
    {
        IClass CreateClass();
    }

_classFactory.CreateClass().Method(....)

So when the parameter HasBilling equals to true then i have to invoke Method() of Class1 implementation, similarly if HasPayment equals to true, Method() of Class2 implementation must be called.

Using Ninject Binding, I tried these bindings, but neither one worked:

Bind<IClass>().To<Class1>().When(x => x.Target.Member.Name.Contains("HasBilling").Equals(true));

Tried this, but no luck:

Bind<IClass>().To<Class1>().WithMetadata("HasBilling", true);

Please can some one help me with what bindings needs to be set to call Class1 , Class2 method( Method ) based on a parameter value( HasBilling,HasPayment ) .

Many Thanks In Advance,

Thanks, WH

If your context is necessary to determine which concrete type to load then you'll need to pass it either to your concrete classes or to the factory. AFAIK there's no way for Ninject to examine your call chain to say "method X is going to be called, so I need to use that information to determine which concrete class to use".

If you change your factory, this problem because very simple:

interface IClassFactory
{
   IClass CreateClass(Object context)
}

class ClassFactory : IClassFactory
{
   IClass CreateClass(Object context)
   {
      if (context.HasBilling)
          return new Class1();

       // default case
       return new Class2();
   }
}

Then you would consume with:

IClassFactory classFactory; // injected
object context;

classFactory.CreateClass(context).Method();

An alternative is to use a proxy pattern. IClass stays the same, do away with IClassFactory . Instead you use a proxy:

public class ClassProxy : IClass
{
    void Method(Object context)
    {
       if (context.HasBilling) 
          new Class1().Method(context);
       else
        //etc
    }
}

In your kernal you'd wire this up as:

kernel.Bind<IClass>().To<ClassProxy>();

You'd also need to make sure your implementations are NOT bound to IClass in the kernel. (So make sure there's you DO NOT have kernel.Bind<IClass>().To<Class1>() .

If you want to take advantage of DI for your implementation classes, however, you could make them self bindable ( kernel.Bind<Class1>().ToSelf() ) and then your ClassProxy could take them as dependencies:

class ClassProxy : IClass
{
    private readonly Class1 _class1;    
    private readonly Class2 _class2;

    public ClassProxy(Class1 class1, Class2 class2){
       _class1 = class1;
       _class2 = class2;
    }

    void Method(object context)
    {
         if (context.HasBilling)
             _class1.Method(context);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM