0

Using Ninject 2.2, I have the following failing test (simplified):

public interface IGenericView<T>
{
}

public interface IDefaultConvention
{
}

public class DefaultConvention : IDefaultConvention
{
}

public class DefaultConventionView : IGenericView<IDefaultConvention>
{ 
}

public class StringView : IGenericView<string>
{  
}

[TestFixture]
public class NinjectTests
{
    private static IKernel _kernel;

    [SetUp]
    public void Setup()
    {
        _kernel = new StandardKernel();
    }

    [Test]
    public void CanResolveAllClassesClosingOpenGenericInterface()
    {
        // Arrange
        _kernel.Bind<IDefaultConvention>().To<DefaultConvention>();
        _kernel.Scan(
            x =>
            {
                x.FromCallingAssembly();
                x.BindWith(new GenericBindingGenerator(typeof(IGenericView<>)));
            });

        // Act
        object target1 = _kernel.Get<IGenericView<IDefaultConvention>>();
        object target2 = _kernel.Get<IGenericView<string>>();

        // Assert
        Assert.IsAssignableFrom<DefaultConventionView>(target1);
        Assert.IsAssignableFrom<StringView>(target2);
        Assert.AreEqual(2, _kernel.GetAll(typeof(IGenericView<>)).Count()); // Always returns 0
    }
}

The first two assertions pass, so I know the types themselves are being bound correctly, but I can't retrieve all the bindings for the open generic interface like I want to. Is this at all possible?

Genyus
  • 28
  • 5

1 Answers1

4

No that is not possible. Where should Ninject know from which types are allowed as generic parameters? Taking your assumption why do you think 2 is the correct value? Why shouldn't IGenericView<int> be returned too? Furthermore, what should be the return type? IEnumerable<IGenericView<>> isn't an allowed runtime type. IEnumerable<IGenericView<object>> probably isn 't what one expects.

GetAll returnes one instance for each binding of the requested type and there is exactly one in this case. You must define a common non generic base interface in this case and register it for each type and call GetAll for this interface.

Remo Gloor
  • 32,665
  • 4
  • 68
  • 98
  • Thanks for your answer, Remo - I understand your point. It didn't seem quite right to begin with, but the only reason I even attempted that route is because GetAll doesn't work with inherited interfaces. If I define `interface IGenericView : IView`, I can't then call `GetAll()` even if I specify `class StringView : GenericView, IView`. This is the fundamental problem I've run up against, where I effectively want to be able to grab all the bindings that are created by the earlier Scan method call. Is there any possibility of achieving this? – Genyus Nov 12 '11 at 09:30
  • You have to define a binding for IView for all classes. Since you are using conventions you can easily do so e.g. using RegexBindingGenerator or your own Generator. – Remo Gloor Nov 12 '11 at 12:02
  • Many hanks for your assistance, Remo. In the end, I decided to go a non-generic route as it was causing me too much hassle, but your response definitely pointed me in the right direction and got me past that immediate hurdle. – Genyus Nov 14 '11 at 23:09