Resolve just one Item in List<Lazy<T>> with Ninject

212 views Asked by At

This is my Scenario:

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

Questions:

Here The list of Animals are Lazily injected into the class Foo.

I want to do something like Line * with Ninject. As you may know the problem is that before resolving a class, GetType() returns Null. So how can I resolve just one of the Items in the list whenever I want?

Can Ninject do such a thing at all or I have to change my DI Container?

2

There are 2 answers

1
Hemario On

You can use the OfType extension method provided in the System.Linq namespace.

var dog = _animals.OfType<Dog>().First();
10
Steven On

This is a chicken and the egg problem: you don't know the type unless you get the value. You can only solve this by adding extra information to the list that is known before hand.

This is a good fit for Lazy<T, TMetadata> which is part of the System.ComponentModel.Composition assembly:

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

As I said in the comments, I'm no Ninject expert, but most things can be done with a framework, even when there is no built-in support for it. This is what I think your registration would look like. I might have the Ninject syntax wrong, but it would look a bit like this:

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);