Inject an instance of Func<IEnumerable<IEtlVisitor>>

Coordinator
Dec 3, 2013 at 12:30 AM
Using plain old constructor injection I know that Simple Injector can provide
Func<IEtlVisitor>
and
IEnumerable<IEtlVisitor>
but I'm unable to configure
Func<IEnumerable<IEtlVisitor>>
is it my mistake or is this not yet possible?
Coordinator
Dec 3, 2013 at 7:24 AM
It depends on what you need. You can do this:
container.RegisterAll<IEtlVisitor>(typeof(Visitor1), typeof(Visitor2));

container.RegisterSingle<Func<IEnumerable<IEtlVisitor>>>(() => container.GetAllInstances<IEtlVisitor>());
However, since the IEnumerable returned from GetAllInstances is a singleton, it's pretty useless to wrap it in a Func<T>.

What is it exactly you want to achieve?
Marked as answer by qujck on 12/3/2013 at 2:04 AM
Coordinator
Dec 3, 2013 at 9:38 AM
Edited Dec 3, 2013 at 9:41 AM
It's a bit early to fully answer your question
What is it exactly you want to achieve?
Currently I have a command handler that takes an instance of the container so that it can call
container.GetAllInstances<IEtlVisitor>()
filter the returned set (based on external configuration), rinse and repeat, all within a single business transaction.

I can remove the dependency on the container and have new instances of the Visitors for each call to the Func<> doing this
container.Register<VisitationHandler2>(() => 
    new VisitationHandler2(() => 
        container.GetAllInstances<IVisitor>()));
(with this class)
public class VisitationHandler2
{
    public readonly Func<IEnumerable<IVisitor>> visitors;
    public int counter = 0;

    public VisitationHandler2(Func<IEnumerable<IVisitor>> visitors)
    {
        this.visitors = visitors;
    }

    public void Execute(IElement element)
    {
        for (int i = 0; i < 2; i++)
        {
            foreach (var visitor in this.visitors())
            {
                counter++1;
            }
        }
    }
}


But wondered if it would work "out of the box".
Coordinator
Dec 3, 2013 at 9:48 AM
Edited Dec 3, 2013 at 9:49 AM
As you've already said - IEnumerable<IVisitor> get re-evaluated for each call.
[Test]
public void RegisterVisitationHandler1_FuncGetAll_GetsNewVisitors()
{
    Container container = new Container();
    container.RegisterAll<IVisitor>(typeof(Visitor1), typeof(Visitor2), typeof(Visitor3));
    container.Register<VisitationHandler1>();

    var result1 = container.GetInstance<VisitationHandler1>();

    var first1 = result1.visitors.ToArray()[0];
    var first2 = result1.visitors.ToArray()[0];

    Assert.That(first1, Is.Not.SameAs(first2));
}
{with this class)
public class VisitationHandler1
{
    public readonly IEnumerable<IVisitor> visitors;
    public int counter = 0;

    public VisitationHandler1(IEnumerable<IVisitor> visitors)
    {
        this.visitors = visitors;
    }

    public void Execute(IElement element)
    {
        foreach (var visitor in this.visitors)
        {
            counter++;
        }
    }
}
It already does it out the box!
Coordinator
Dec 3, 2013 at 10:09 AM
So that answers your question?
Coordinator
Dec 3, 2013 at 1:18 PM
Yes