Как получить все привязки для универсального интерфейса с помощью Ninject

#generics #dependency-injection #ninject #ninject-2 #ninject-extensions

#общие сведения #внедрение зависимостей #ninject #ninject-2 #ninject-расширения

Вопрос:

Используя Ninject 2.2, у меня есть следующий неудачный тест (упрощенный):

 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
    }
}
  

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

Ответ №1:

Нет, это невозможно. Откуда Ninject должен знать, какие типы разрешены в качестве универсальных параметров? Исходя из вашего предположения, почему вы думаете, что 2 является правильным значением? Почему IGenericView<int> также не должно быть возвращено? Кроме того, каким должен быть возвращаемый тип? IEnumerable<IGenericView<>> не является допустимым типом среды выполнения. IEnumerable<IGenericView<object>> вероятно, это не то, что можно ожидать.

GetAll возвращает один экземпляр для каждой привязки запрошенного типа, и в данном случае существует ровно один. В этом случае вы должны определить общий не универсальный базовый интерфейс и зарегистрировать его для каждого типа и вызвать GetAll для этого интерфейса.

Комментарии:

1. Спасибо за твой ответ, Ремо — я понимаю твою точку зрения. С самого начала это казалось не совсем правильным, но единственная причина, по которой я вообще попытался использовать этот маршрут, заключается в том, что GetAll не работает с унаследованными интерфейсами. Если я определю interface IGenericView<T> : IView , я не смогу затем вызвать, GetAll<IView>() даже если я укажу class StringView : GenericView<string>, IView . Это фундаментальная проблема, с которой я столкнулся, когда я фактически хочу иметь возможность захватывать все привязки, созданные предыдущим вызовом метода сканирования. Есть ли какая-либо возможность достичь этого?

2. Вы должны определить привязку для IView для всех классов. Поскольку вы используете соглашения, вы можете легко сделать это, например, с помощью RegexBindingGenerator или вашего собственного генератора.

3. Большое спасибо за твою помощь, Римо. В конце концов, я решил пойти нестандартным путем, поскольку это доставляло мне слишком много хлопот, но ваш ответ определенно указал мне правильное направление и помог преодолеть это непосредственное препятствие.