开发者

Ninject Cascading Inection with IList

开发者 https://www.devze.com 2023-02-02 12:24 出处:网络
I am trying to use Ninject to implement cascading injection into a class that contains an IList field.It seems that, unless I specifically specify each binding to use in the kernel.Get method, the ILi

I am trying to use Ninject to implement cascading injection into a class that contains an IList field. It seems that, unless I specifically specify each binding to use in the kernel.Get method, the IList property is always injected with a list of a single default object.

The following VSTest code illustrates the problem. The first test fails because the IList field contains one MyType object with Name=null. The second test passes, but I had to specifically tell Ninject what constructor arguments to use. I am using the latest build from the ninject.web.mvc project for MVC 3.

Does Ninject specifically treat IList different, or is there a better way to handle this? Note that this seems to only be a problem when using an IList. Createing a custom collection object that wraps IList works as expected in the first test.

[TestClass()]
public class NinjectTest
{
    [TestMethod()]
    public void ListTest_Fails_NameNullAndCountIncorrect()
    {
        var kernel = new Ninject.StandardKernel(new MyNinjectModule());
        var target = kernel.Get<MyModel>();
        var actual = target.GetList();

        // Fails. Returned value is set to a list of a single object equal to default(MyType) 
        Assert.AreEqual(2, actual.Count());  

        // Fails because MyType object is initialized with a null "Name" property
        Assert.AreEqual("Fred", actual.First().Name); 
    }

    [TestMethod()]
    public void ListTest_Passes_SeemsLikeUnnecessaryConfiguration()
    {
        var kernel = new Ninject.StandardKernel(new MyNinjectModule());

        var target = kernel.Get<MyModel>(new ConstructorArgument("myGenericObject", kernel.Get<IGenericObject<MyType>>(new ConstructorArgument("myList", kernel.Get<IList<MyType>>()))));

        var actual = target.GetList();
        Assert.AreEqual(2, actual.Count());  
        Assert.AreEqual("Fred", actual.First().Name); 
    }
}

public class MyNinjectModule : NinjectModule
{
    public override void Load()
    {
        Bind<IList<MyType>>().ToConstant(new List<MyType> { new MyType { Name = "Fred" }, new MyType { Name = "Bob" } });
        Bind<IGenericObject<MyType>>().To<StubObject<MyType>>();
    }
}

public class MyModel
{
    private IGenericObject<MyType> myGenericObject;

    public MyModel(IGenericObject<MyType> myGenericObject)
    {
        this.myGenericObject = myGenericObject;
    }

    public IEnumerable<MyType> GetList()
    {
        return myGenericObject.GetList();
    }
}

public interface IGenericObject<T>
{
    IList<T> GetList();
}

public class StubObject<T> : IGenericObject<T>
{
    private IList<T> _myList;

    public StubObject(IList<T> myList)
    {
        _myList = myList;
    }

    public IList&开发者_如何学Golt;T> GetList()
    {
        return _myList;
    }
}

public class MyType
{
    public String Name { get; set; }
}


lists, collections and arrays are handled slightly different. For those types ninject will inject a list or array containing an instance of all bindings for the generic type. In your case the implementation type is a class which is aoutobound by default. So the list will contain one instance of that class. If you add an interface to that class and use this one the list will be empty.

0

精彩评论

暂无评论...
验证码 换一张
取 消