Внедрение IEnumerable в конструктор с помощью фабричного метода Ninject

#c# #dependency-injection #ninject

#c# #внедрение зависимостей #ninject

Вопрос:

Я пытаюсь внедрить IEnumerable в конструктор с помощью Ninject.

Мой конструктор выглядит следующим образом:

 public MatrixViewModel(IEnumerable<FooViewModel> fooViewModels)
{
    _fooViewModels = fooViewModels;
}
  

Мой модуль Ninject выглядит следующим образом:

 public class MainModule : NinjectModule
{
    public override void Load()
    {
        Bind<IEnumerable<FooViewModel>>()
            .ToMethod(context => GetFooViewModels())
            .InSingletonScope(); // this binding is not working
    }

    private IEnumerable<FooViewModel> GetFooViewModels()
    {
        // returns a bunch of foo view models
    }
}
  

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

Как вы вводите IEnumerable с помощью Ninject?

Редактировать

Более подробная информация о моем заводском методе:

 private IEnumerable<FooViewModel> GetFooViewModels()
{
    return new[]
    {
        new FooViewModel
        {
            Bar = new BarViewModel
            {
                X = 1,
                Y = 2
            },
            Misc = "Hello"
        },
        new FooViewModel
        {
            Bar = new BarViewModel
            {
                X = 3,
                Y = 4
            },
            Misc = "Goodbye"
        },
        // etc.....
    };
}
  

Правка 2

Основываясь на ответе Ремо, одним из возможных решений является использование цикла foreach для привязки моделей представления по одной за раз:

 foreach (var fooViewModel in GetFooViewModels())
{
    Bind<FooViewModel>().ToConstant(fooViewModel);
}
  

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

1. Я не уверен, что коллекция поддерживает или ToMethod работает таким образом. Это должно было бы сработать, хотя: Bind<MatrixViewModel>().ToMethod(context => new MatrixViewModel(GetFooViewModels())) . Кроме того, вы можете добавить свой собственный ответ на свой вопрос и принять его, если ответ Remo был не совсем на том уровне, который вы хотели принять в качестве ответа.

2. @Merlyn, это хороший момент… просто «поднимитесь на уровень» и привяжите всю MatrixViewModel (хотя моя модель реального представления имеет несколько параметров, поэтому было бы немного сложнее связать все это). Что касается того, почему я не включил свое решение в ответ, я мог бы спросить вас то же самое о вашем комментарии 🙂

3. Верно 🙂 Для этого определенно существует несколько допустимых решений…

Ответ №1:

Перечисляемые обрабатываются Ninject по-разному. Просто предоставьте привязки для всех моделей представления. Для перечислимых объектов Ninject создаст экземпляр каждой применяемой привязки и передаст их как IEnumerable .

например

 Bind<FooViewModel>().To<FooViewModel1>();
Bind<FooViewModel>().To<FooViewModel2>();
  

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

1. Ремо, спасибо за твой ответ, но на самом деле это не решает мою ситуацию. Мой фабричный метод возвращает кучу экземпляров FooViewModel, а не кучу объектов, которые наследуются от FooViewModel.

2. В настоящее время вы не можете использовать привязки для IEnumerable, IList, списка и массивов, потому что они обрабатываются особым образом. К сожалению, вам придется немного поработать, используя либо ICollection, либо создавая свой собственный интерфейс из IEnumerable<FooViewModel>

3. Ремо, спасибо и 1. Я думаю, что я нашел способ заставить его работать, не создавая свой собственный интерфейс (см. Мою правку 2). Не могли бы вы оставить комментарий, чтобы подтвердить, что мое решение будет работать надежно? Спасибо.

4. Ремо, я решил также использовать это в качестве ответа.

Ответ №2:

Основываясь на ответе Ремо, одним из возможных решений является использование foreach цикла для привязки моделей представления по одной за раз:

 foreach (var fooViewModel in GetFooViewModels())
{
    Bind<FooViewModel>().ToConstant(fooViewModel);
}
  

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

1. Это должно выполняться так же, как и исходная привязка, за исключением того, что GetFooViewModels() вызывается во время создания привязок, а в исходной привязке он вызывается при первом разрешении.

2. Ремо, другое отличие от моей оригинальной привязки заключается в том, что эта действительно работает 🙂 Но спасибо вам за продолжение.

3. @Remo: У меня сложилось впечатление, что NInject использует коллекции со специальным корпусом, поэтому он разрешит все привязки типа в коллекции. И если это особые случаи, я не удивлюсь, если это не разрешится другим способом. Поведение в OP, похоже, соответствует моему предположению. github.com/ninject/ninject/wiki/Multi-injection

Ответ №3:

Из вашего вопроса:

 Bind<IEnumerable<FooViewModel>>()
    .ToMethod(context => GetFooViewModels())
  

Я не уверен, что поддержка коллекций или ToMethod работает таким образом.

Это должно сработать, хотя:

 Bind<MatrixViewModel>()
    .ToMethod(context => new MatrixViewModel(GetFooViewModels()))
  

Конечно, насколько полезно это решение, зависит от того, как вы создаете свои представления.

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

1. Вы вводите в свою модель представления, поэтому это не относится к вашей ситуации. Но если вы используете WPF / MVVM и пытаетесь внедрить модель представления в представление, мне нравится удалять любую концепцию моделей представления из моего представления и просто устанавливать представление DataContext в ToMethod .