2
votes

Consider the following code:

using System.Collections.ObjectModel;
using Ninject;

namespace ConsoleApplication2 {

  public interface IComponent {
    //stuff
  }

  public class Component : IComponent {
    // implementation of stuff
  }

  public class Aggregator {
    private ObservableCollection<IComponent> _componentList;

    public Aggregator(ObservableCollection<IComponent> componentList) {
        _componentList = componentList;
    }

    public ObservableCollection<IComponent> ComponentList { get { return _componentList; }   }
  }

  public class Bindings : Ninject.Modules.NinjectModule {

    public override void Load() {
        Bind<IComponent>().To<Component>();
    }
  }

  public class MyProgram {

    public static void Main() {
        Ninject.IKernel kernel = new StandardKernel(new Bindings());
        var myAgg = kernel.Get<Aggregator>();
    }
  }
}

For me this fails with a run-time exception of:

Ninject.ActivationException was unhandled HResult=-2146233088 Message=Error activating ObservableCollection{IComponent} using implicit self-binding of ObservableCollection{IComponent} Several constructors have the same priority. Please specify the constructor using ToConstructor syntax or add an Inject attribute.

Constructors: ObservableCollection1(List{IComponent} list) [__DynamicallyInvokable]ObservableCollection1(IEnumerable{IComponent} collection)

Activation path: 2) Injection of dependency ObservableCollection{IComponent} into parameter componentList of constructor of type Aggregator 1) Request for Aggregator

Suggestions: 1) Ensure that the implementation type has a public constructor. 2) If you have implemented the Singleton pattern, use a binding with InSingletonScope() instead.

Source=Ninject StackTrace: at Ninject.Activation.Providers.StandardProvider.Create(IContext context) at Ninject.Activation.Context.ResolveInternal(Object scope) at Ninject.Activation.Context.Resolve() at Ninject.KernelBase.<>c__DisplayClass15.b__f(IBinding binding) at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable1 source) at Ninject.Planning.Targets.Target1.GetValue(Type service, IContext parent) at Ninject.Planning.Targets.Target1.ResolveWithin(IContext parent) at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.b__2(ITarget target) at System.Linq.Enumerable.WhereSelectArrayIterator2.MoveNext() at System.Linq.Buffer1..ctor(IEnumerable1 source) at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source) at Ninject.Activation.Providers.StandardProvider.Create(IContext context) at Ninject.Activation.Context.ResolveInternal(Object scope) at Ninject.Activation.Context.Resolve() at Ninject.KernelBase.<>c__DisplayClass15.b__f(IBinding binding) at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at System.Linq.Enumerable.<CastIterator>d__b11.MoveNext() at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source) at Ninject.ResolutionExtensions.Get[T](IResolutionRoot root, IParameter[] parameters) at ConsoleApplication2.MyProgram.Main() in C:\Users\user.name\workspace\vs2010\ConsoleApplication2\ConsoleApplication2\Program.cs:line 36 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:

The error is being caused by the ObservableCollection implicit constructor binding. Can somebody provide any ideas or pointers on how to resolve this?

1

1 Answers

3
votes

As ninject says, it doesn't know how to construct the ObservableCollection<> because it has two publicly accessible constructors with the same argument count.

When there are multiple constructors, ninject checks for which it can resolve the most arguments, and chooses this constructor. There are

  • ObservableCollection<T>(IEnumerable<T>)
  • ObservableCollection<T>(List<T>)

both of which ninject could use (as long as you have defined a binding for T).

Now, the easiest way to override that behavior would be to place an [Inject] attribute on the ctor you want ninject to use. Since the source code of ObservableCollection<> is not under your control, you can't do it . What you can do is specifying a binding for the ObservableCollection<> which tells Ninject how to create it. You can do this using the .ToConstructor() syntax (as the exception stated):

kernel
  .Bind<ObservableCollection<IComponent>>()
  .ToConstructor(x => 
     new ObservableCollection<IComponent>(x.Inject<IList<IComponent>>()));

In theory you also could use the .ToMethod() binding, but i would not recommend it. Also see What's the difference between .ToConstructor and .ToMethod in Ninject 3?