#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. Большое спасибо за твою помощь, Римо. В конце концов, я решил пойти нестандартным путем, поскольку это доставляло мне слишком много хлопот, но ваш ответ определенно указал мне правильное направление и помог преодолеть это непосредственное препятствие.