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 Bazing开发者_如何学PythonaConsoleLogger
is not a dependency of anything, it will not be created by the dependency injection container. What is the best way to fix this?
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.
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.
A IListener
marker interface could be added to the class. In the application start-up code, I could then pull all IListener
instances from the container in addition to the main program instance:
container.Resolve<IEnumerable<IListener>>(); // just to create the listeners
var program = container.Resolve<Program>();
program.Run();
Another option is to use an IStartable
interface (inspired by Autofac) which solves a more general problem, i.e. the launching of multiple services at start-up. In the case of an event listener class, the Start
method could be used to subscribe to the event (thus removing this responsibility from the constructor) or simply do nothing. The Program
class could be one of the IStartable
implementations.
var startables = container.Resolve<IEnumerable<IStartable>>();
foreach (var startable in startables)
{
startable.Start();
}
精彩评论