Ninject在Kernel.Get和构造函数注入之间表现不同

3

我有什么:

public interface IBla
{
}

public class Bla1 : IBla
{
}

public class Bla : IBla
{
}

public class Consumer
{
    private readonly IBla[] _array;

    public Consumer(IBla[] array)
    {
        _array = array;
    }
}

public static class NinjectExtensions
{
      public class BindListExpression<TElement>
      {
          private readonly IKernel _kernel;
          private readonly List<Type> _types = new List<Type>();

          public BindListExpression(IKernel kernel)
          {
              _kernel = kernel;
          }

          public BindListExpression<TElement> ImplementedBy<T>() where T : TElement
          {
              var type = typeof(T);

              _kernel.Bind<T>().To(type);
              _types.Add(type);

              return this;
          }

          public void Bind()
          {
              Func<TElement[]> createObjects = () =>
              {
                  var sourceArray = new TElement[_types.Count];
                  for (var i = 0; i < _types.Count; i++)
                  {
                      var value = _kernel.Get(_types[i]);
                      sourceArray[i] = (TElement)value;
                  }
                  return sourceArray;
              };

              _kernel.Bind<TElement[]>().ToMethod(x => createObjects().ToArray());
              _kernel.Bind<List<TElement>>().ToMethod(x => (createObjects().ToList()));
              _kernel.Bind<IEnumerable<TElement>>().ToMethod(x => createObjects().ToList());
          }
      }
      public static BindListExpression<T> ListOf<T>(this IKernel kernel)
      {
          return new BindListExpression<T>(kernel);
      }
  }

用法:

// Binds items in the given order as a list (Ninject does not guarantee the given order so I use this mechanism).
kernel.ListOf<IBla>()
    .ImplementedBy<Bla1>()
    .ImplementedBy<Bla>()
    .Bind();

var consumer = kernel.Get<Consumer>(); // result: consumer._array is empty?! --> what is imo wrong
var array = kernel.Get<IBla[]>(); // result: Bla1, Bla --> correct

为什么Ninject在使用Get<IBla[]>()和带有参数IBla[]的构造函数时结果不同?
2个回答

3
使用构造函数注入时,ninject将ctor参数IBla[]转换为IResolutionRoot.GetAll().ToArray()。这就是实现多重注入支持的方式。所以不能在ctor请求中使用IResolutionRoot.Get()-但你仍然可以手动执行此操作。
对于所有由ninject转换为多重注入的集合类型(AFAIR数组、IList、IEnumerable,但不包括ICollection),这都是正确的。
我建议使用另一个集合接口(例如ICollection)或集合实现作为构造函数参数。这将导致ctor注入和IResolutionRoot.Get调用的一致行为。

谢谢您的回复。是否可以禁用多重注入支持或列表/数组注入支持?我真正想要的是绑定一系列项目,其中给定的顺序用于解析该绑定列表。 Ninject在解析列表/数组时不能保证正确的顺序。 - Rookian
你不能通过更改设置来禁用它。你可能可以替换一些内部组件,但我真的不建议这样做。所以你能做的就是使用注入另一种集合类型,这种类型不会被ninject检测为“多重注入”。 - BatteryBackupUnit

0

可以按特定顺序绑定数组依赖项。您只需要像这样在Ninject中注册它们。

_kernel.Bind<Bla1>().ToSelf();
_kernel.Bind<Bla>().ToSelf();
_kernel.Bind<IConsumer>().To<Consumer>()
    .WithConstructorArgument("array", 
        new IBla[] { 
            _kernel.Get<Bla1>(), 
            _kernel.Get<Bla>() 
        });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接