2017-10-11 42 views
1

审查下面的代码,在那里照顾的情况下与接口单,并命名为结合数组注射,使用了抽象工厂这里Ninject如何避免多个名称绑定

Parameterized Factories Using Ninject

建议

这里面临的挑战是,我需要引入IEnumerable<T> bankingOperationList而不是T bankingOperationList,因为对于命名绑定,它将始终使用抽象工厂注入Func<string,T> bankingOperationFunc,但如果我不使用上面建议的IEnumerable<T>,则会导致异常,因为这会导致偶数非命名单绑定,我需要使用类似: bankingOperationList.FirstOrDefault().Withdraw(),即使我知道只会有一个依赖。 另一个挑战是,对于某些命名的绑定,在少数情况下它有30-40个绑定,当我可以将T bankingOperationList默认为空时,它将被不必要地填充,因为它不是必需的。请让我知道,如果这个问题需要进一步澄清。下方的工作控制台项目。

public interface IBankingOperation 
{ 
    void Withdraw(); 
} 

public class BankingOperationOne : IBankingOperation 
{ 
    public BankingOperationOne() 
    { 
     Console.WriteLine("Testing Constructor :: One :: Empty"); 
    } 

    public void Withdraw() 
    { 
     Console.WriteLine("Money Withdrawl Operation One"); 
    } 
} 

public class BankingOperationTwo : IBankingOperation 
{ 
    public BankingOperationTwo() 
    { 
     Console.WriteLine("Testing Constructor :: Two :: Empty"); 
    } 

    public void Withdraw() 
    { 
     Console.WriteLine("Money Withdrawl Operation Two"); 
    } 
} 

// Ninject Bindings 
public class Bindings : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IBankingOperation>().To<BankingOperationOne>() 
           .Named("A"); 

     Bind<IBankingOperation>().To<BankingOperationTwo>() 
           .Named("B"); 

     Bind<Func<string,IBankingOperation>>().ToMethod(ctx => name => ctx.Kernel.Get<IBankingOperation>(name)); 
    } 
} 

public class BankTran<T> where T : IBankingOperation 
{ 
    private IEnumerable<T> bankingOperationList = null; 

    private Func<string,T> bankingOperationFunc; 

    public BankTran(IEnumerable<T> boList = null, 
        Func<string,T> boFunc = null) 
    { 
     bankingOperationList = boList; 
     bankingOperationFunc = boFunc; 
    } 

    public void DoOperation(string identifier = null) 
    { 
     if(bankingOperationFunc != null)   
      bankingOperationFunc(identifier).Withdraw(); 
     else 
      bankingOperationList.FirstOrDefault().Withdraw();  

     Console.WriteLine("Transaction Successful "); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var kernel = new StandardKernel(); 

     kernel.Load(Assembly.GetExecutingAssembly()); // Load from Bindings (derived from NinjectModule) 

     var transaction = kernel.Get<BankTran<IBankingOperation>>(); 

     transaction.DoOperation("A"); 
    } 
} 

编辑1,由JBL

public interface IBankingOperation<T> 
{ 
    void Withdraw(); 
} 

public class BankingOperationOne : IBankingOperation<TestOne> 
{ 
    public BankingOperationOne() 
    { 
     Console.WriteLine("Testing Constructor :: One :: Empty"); 
    } 

    public void Withdraw() 
    { 
     Console.WriteLine("Money Withdrawl Operation One"); 
    } 
} 

public class BankingOperationTwo : IBankingOperation<TestTwo> 
{ 
    public BankingOperationTwo() 
    { 
     Console.WriteLine("Testing Constructor :: Two :: Empty"); 
    } 

    public void Withdraw() 
    { 
     Console.WriteLine("Money Withdrawl Operation Two"); 
    } 
} 

public class TestOne { } 

public class TestTwo { } 

// Ninject Bindings 
public class Bindings : NinjectModule 
{ 
    public override void Load() 
    { 

     Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().Named("A"); 

     Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().Named("B"); 

     Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().WhenInjectedInto(typeof(BankTran<TestOne>)); 

     Bind<Func<string, IBankingOperation<TestOne>>>().ToMethod(ctx => name => ctx.Kernel.Get<IBankingOperation<TestOne>>(name)); 

     Bind<IBankingOperation<TestTwo>>().To<BankingOperationTwo>(); 
    } 
} 

public class BankTran<T> where T : class 
{ 
    private IBankingOperation<T> bankingOperation; 

    private Func<string, IBankingOperation<T>> bankingOperationFunc; 

    public BankTran(IBankingOperation<T> bo = null, 
        Func<string, IBankingOperation<T>> boFunc = null) 
    { 
     bankingOperation = bo; 
     bankingOperationFunc = boFunc; 
    } 

    public void DoOperation(string identifier = null) 
    { 
     if (bankingOperationFunc != null && identifier != null) 
      bankingOperationFunc(identifier).Withdraw(); 
     else if (bankingOperation != null) 
      bankingOperation.Withdraw(); 

     Console.WriteLine("Transaction Successful "); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var kernel = new StandardKernel(new NinjectSettings { AllowNullInjection = true}); 

     kernel.Load(Assembly.GetExecutingAssembly()); // Load from Bindings (derived from NinjectModule) 

     var transaction = kernel.Get<BankTran<TestOne>>("A"); // Not Working 

     // var transaction = kernel.Get<BankTran<TestOne>>(); // Working 

     transaction.DoOperation(); 
    } 
} 
+0

注入'Func'是完成工作的一种方法。使用[策略模式](https://stackoverflow.com/a/31971691/)是另一个。这将是清单手头上的“清单”的更清晰的解决方案。也就是说,你不清楚你想要解决什么问题 - 它是从列表中获得“默认”操作吗? – NightOwl888

+0

@ NightOwl888问题是多个相同类型的绑定将由'Func '处理,另一个'IEnumerable '不被使用,它只需要一对一/唯一/未命名的绑定,但仍然需要一个集合,否则对于命名绑定导致异常,它们被不必要地填充。请运行代码并尝试'T bankingOperation'而不是'Banknoperable bankingOperationList'在'BankTran '中,您将会得到我正在谈论的问题 –

+0

@ NightOwl888我回顾了您提供的解决方案,它避免了需要'Func ','ICarFactory []'本身找到了正确的对象,但这样我就能够使当前的解决方案工作得很好,我只是想避免命名绑定需求来填充集合,但Ninject仍然存在线索少在这种情况下,并希望收集填写 –

回答

1

假设BankingOperationOne基于响应是默认的行为, 将在您的Load方法以下行应允许T更换IEnumerable<T>你BankTran的构造函数:

Bind<IBankingOperation>().To<BankingOperationOne>().WhenInjectedInto(typeof(BankTran<>)); 

另一种解决方案是只定义了一个名为默认行为

Bind<IBankingOperation>().To<BankingOperationOne>().Named("__DefaultBehaviour"); 

结合然后

public void DoOperation(string identifier = "__DefaultBehaviour") 
     { 
      if (bankingOperationFunc != null) 
       bankingOperationFunc(identifier).Withdraw(); 

      Console.WriteLine("Transaction Successful "); 
     } 

编辑:

您应该使用Ninject.Extenstions.Factory NuGet包。 使用这个包,下面的代码似乎满足您的需求。

public interface IBankingOperation<T> 
{ 
    void Withdraw(); 
} 

public interface IBankingOperationFactory<T> 
{ 
    IBankingOperation<T> GetBankingOperation(string name); 
} 

public class BankingOperationOne : IBankingOperation<TestOne> 
{ 
    public BankingOperationOne() 
    { 
     Console.WriteLine("Testing Constructor :: One :: Empty"); 
    } 

    public void Withdraw() 
    { 
     Console.WriteLine("Money Withdrawl Operation One"); 
    } 
} 

public class BankingOperationTwo : IBankingOperation<TestTwo> 
{ 
    public BankingOperationTwo() 
    { 
     Console.WriteLine("Testing Constructor :: Two :: Empty"); 
    } 

    public void Withdraw() 
    { 
     Console.WriteLine("Money Withdrawl Operation Two"); 
    } 
} 

public class TestOne { } 

public class TestTwo { } 

// Ninject Bindings 
public class Bindings : NinjectModule 
{ 
    public override void Load() 
    { 

     Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().Named("A"); 

     Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().Named("B"); 

     Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().WhenInjectedInto(typeof(BankTran<TestOne>)); 

     Bind<IBankingOperationFactory<IBankingOperation<TestOne>>>().ToFactory(); 

     Bind<IBankingOperation<TestTwo>>().To<BankingOperationTwo>(); 
    } 
} 

public class BankTran<T> where T : class 
{ 
    private IBankingOperation<T> bankingOperation; 

    private IBankingOperationFactory<T> _bankingOperationFactory; 

    public BankTran(IBankingOperation<T> bo = null, 
        IBankingOperationFactory<T> bankingOperationFactory = null) 
    { 
     bankingOperation = bo; 
     _bankingOperationFactory = bankingOperationFactory; 
    } 

    public void DoOperation(string identifier = null) 
    { 
     if (_bankingOperationFactory != null && identifier != null) 
      _bankingOperationFactory.GetBankingOperation(identifier).Withdraw(); 
     else if (bankingOperation != null) 
      bankingOperation.Withdraw(); 

     Console.WriteLine("Transaction Successful "); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var kernel = new StandardKernel(new NinjectSettings { AllowNullInjection = true }); 

     kernel.Load(Assembly.GetExecutingAssembly()); // Load from Bindings (derived from NinjectModule) 

     var transaction = kernel.Get<BankTran<TestOne>>(); 

     transaction.DoOperation(); 
     transaction.DoOperation("A"); 
     transaction.DoOperation("B"); 
    } 
} 
+0

感谢您的详细信息,请检查标记为**编辑1的问题中的编辑,基于jbl的响应**您的代码帮助我运行主要方法中标记的部分没有明确的名称,但它仍然不能帮助运行名称为“A”的版本,这是我的主要挑战 –

+0

@MrinalKamboj不应该他不在你编辑的例子中工作线'var transaction = kernel.Get >(“A”);'? – jbl

+0

这是我标记为非工作的帽子,只是我已将该部分包含在代码中,以便您可以运行并查看错误。没有“A”的其他部分正在工作,正如上面的评论中所建议的那样。 –