Инъекция Ninject Cascading с IList - PullRequest
       0

Инъекция Ninject Cascading с IList

1 голос
/ 04 января 2011

Я пытаюсь использовать Ninject для реализации каскадного внедрения в класс, содержащий поле IList. Кажется, что, если я не укажу каждую привязку для использования в методе kernel.Get, свойство IList всегда внедряется со списком одного объекта по умолчанию.

Следующий код VSTest иллюстрирует проблему. Первый тест не пройден, поскольку в поле IList содержится один объект MyType с именем = null. Второй тест пройден, но мне пришлось специально указать Ninject, какие аргументы конструктора использовать. Я использую последнюю сборку из проекта ninject.web.mvc для MVC 3.

Специально ли Ninject относится к IList по-другому или есть лучший способ справиться с этим? Обратите внимание, что это кажется проблемой только при использовании IList. Создание пользовательского объекта коллекции, заключающего в себя IList, работает, как и ожидалось, в первом тесте.

[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<T> GetList()
    {
        return _myList;
    }
}

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

1 Ответ

4 голосов
/ 10 января 2011

списки, коллекции и массивы обрабатываются немного иначе. Для этих типов ninject вставит список или массив, содержащий экземпляр всех привязок для универсального типа. В вашем случае типом реализации является класс, который по умолчанию является автоматически связанным. Таким образом, список будет содержать один экземпляр этого класса. Если вы добавите интерфейс к этому классу и будете использовать его, список будет пустым.

...