Ninject如何避免多个名称绑定的数组注入

时间:2017-10-11 10:33:05

标签: c# dependency-injection ninject

查看以下代码,在哪里处理具有接口的单个​​绑定和命名绑定的情况,按照此处的建议使用抽象工厂

Parameterized Factories Using Ninject

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

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();
    }
}

1 个答案:

答案 0 :(得分:1)

假设BankingOperationOne是您的默认行为, 在Load方法中添加以下行应该允许在BankTran构造函数中用IEnumerable<T>替换T

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");
    }
}