views:

76

answers:

3

When we use a dependency injection container, ideally we pull only a single-top level object from it (e.g. an instance of Program) and let the rest of the application be composed automatically by the container.

However, sometimes there are objects which are not a dependency of anything else, yet we want to have them in the object graph. For example, I could have a Notifier class with a Bazinga event, and this BazingaConsoleLogger class:

public class BazingaConsoleLogger
{
    private readonly Notifier notifier;

    public BazingaConsoleLogger(Notifier notifier)
    {
        this.notifier = notifier;
        this.notifier.Bazinga += HandleBazinga;
    }

    private void HandleBazinga(object sender, EventArgs args)
    {
        Console.WriteLine("Bazinga!");
    }
}

Because BazingaConsoleLogger is not a dependency of anything, it will not be created by the dependency injection container. What is the best way to fix this?

+4  A: 

If BazingaConsoleLogger is a service and not a dependency of anything, then it's not used anywhere in your program, so the class can be deleted. Less code FTW! :-)

I don't think that's what you really mean, so can you further explain how you are currently using BazingaConsoleLogger? If you are in fact using BazingaConsoleLogger, you already have a dependency (explicit or not) to BazingaConsoleLogger.

EDIT: to wire events loosely I use Windsor's Event Wiring facility. If your container doesn't have anything like it, it shouldn't be hard to code it, here are the general principles.

Mauricio Scheffer
The desired effect is to have console output showing Bazinga events. In my example, this desired effect can be achieved simply by creating `BazingaConsoleLogger`. However, since no other class uses BazingaConsoleLogger as a dependency, the dependency injection container will never create it. In other words, the existence of a `BazingaConsoleLogger` instance is a desired feature of the composition, but this does not follow automatically by following dependencies.
Wim Coenen
@Wim Coenen: edited my answer WRT events.
Mauricio Scheffer
A: 

If I understand correctly you want to register the HandleBazinga to be registered to the Notifier class. It seems you are trying to abuse your dependency injection framework for this. Perhaps you should just register the event in the startup path of your application. For instance, look at this registration for an ASP.NET forms application:

protected void Application_Start(Object sender, EventArgs e) 
{
    Notifier notifier = new Notifier();

    notifier.Bazinga += (sender, e) =>
    {
        Console.WriteLine("Bazinga!");
    };

    RegisterSingleNotifierToDependencyInjectionFramework(notifier);
}

I hope this helps.

Steven
+2  A: 

In Windsor you could hack something like this:

container.Register(
   Component.For<Notifier>()
      .OnCreate((kernel, notifier) => 
         notifier.Bazinga += kernel.Resolve<BazingaConsoleLogger>().HandleBazinga)
);

however I agree with Mauricio Scheffer and I would treat this as smell and rethink your design in this case.

Krzysztof Koźmic