2013-07-24 8 views
1

Это мой сценарий:Resolve только один элемент в списке <Lazy<T>> с Ninject

public class Foo 
    { 
     private readonly List<Lazy<IAnimal>> _animals; 

     public Foo(List<Lazy<IAnimal>> animals) 
     { 
      _animals = animals; 
     } 

     public void Bark() 
     { 
      //Line: * 
      var dog = _animals.First(p => p.GetType() == typeof (Dog)).Value; 
     } 

     Public void Mio() 
     { 
      //Line: * 
      var dog = _animals.First(p => p.GetType() == typeof (Cat)).Value; 
     } 
    } 

    public class Dog:IAnimal 
    { 
    } 

    public class Cat:IAnimal 
    { 
    } 

    public interface IAnimal 
    { 
    } 

Вопросы:

Вот список животных Лениво вводили в класс Foo.

Я хочу сделать что-то вроде Line * с Ninject. Как вы знаете, проблема в том, что до разрешения класса GetType() возвращает Null. Итак, как я могу разрешить только один из элементов в списке, когда захочу?

Может ли Ninject вообще что-либо предпринять или мне нужно изменить мой контейнер DI?

+0

Поскольку вы заинтересованы в одном 'экземпляра Dog' в' метод Bark', почему вы не просто впрыснуть, что однократное Экземпляр «Собака» в конструкторе Foo? – Steven

+0

@Steven см. Мое обновление. –

+0

Итак, почему бы не ввести собаку и кошку? Если у вас есть еще больше этих методов, вы можете нарушить [Принцип единой ответственности] (http://en.wikipedia.org/wiki/Single_responsibility_principle). – Steven

ответ

-1

Вы можете использовать метод расширения OfType, предоставляемый в пространстве имен System.Linq.

var dog = _animals.OfType<Dog>().First(); 
+0

Как я уже сказал, тип не определяется до разрешения. так что это невозможно. –

0

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

Это хорошо подходит для Lazy<T, TMetadata>, который является частью System.ComponentModel.Composition сборки:

public class Foo 
{ 
    private readonly List<Lazy<IAnimal, Type>> _animals; 

    public Foo(List<Lazy<IAnimal, Type>> animals) 
    { 
     _animals = animals; 
    } 

    public void Bark() 
    { 
     var dog = _animals.First(p => p.Metadata == typeof(Dog)).Value; 
    } 
} 

Update

Как я уже говорил в комментариях, я не Эксперт Ninject, но большинство вещей можно сделать с помощью фреймворка, даже если для него нет встроенной поддержки. Вот что я думаю, что ваша регистрация будет выглядеть. Я мог бы иметь синтаксис неправильно Ninject, но это будет выглядеть немного так:

var list = new List<Lazy<IAnimal, Type>>(); 

list.Add(new Lazy<IAnimal, Type>(() => kernel.Get<Dog>(), typeof(Dog))); 
list.Add(new Lazy<IAnimal, Type>(() => kernel.Get<Pussy>(), typeof(Pussy))); 
list.Add(new Lazy<IAnimal, Type>(() => kernel.Get<Horse>(), typeof(Horse))); 

kernel.Bind<List<Lazy<IAnimal, Type>>().ToConstant(list); 
+0

Спасибо за ваш ответ @Steven. Но как я могу «Связывать» это теперь в моем корне композиции? как я могу отправить «Метаданные»? –

+0

Вам нужно будет сделать это вручную. Для этого нет встроенной поддержки. Единственным контейнером, который имеет встроенную поддержку Lazy , является [Autofac] (http://code.google.com/p/autofac/wiki/Metadata), но я бы не переключился только из-за этого , Вам будет довольно легко зарегистрировать свою коллекцию (хотя я не эксперт по Ninject). – Steven

+0

Извините, но я не знаю, как это сделать вручную? Если 'Ninject' не поддерживает это, так как я могу это сделать? –