Design Injection Alternatives (Windsor Castle)

I like the constructor injection for dependency injection. This makes it clear about type problems and helps with the ability to check.

I like the constructor injection, in most places ...

An example entry where I don't like it. If I have a base class from which many other classes inherit, and I want all these classes to use an instance of my ILogger (or something else), and I don't need a static factory (Logger.Instance) .. I don't want declare a constructor for each subclass that accepts ILogger.

So, I could have my base class declare the registrar as a property and enter it this way

public class MyBaseClass { public ILogger Logger { get; set; } } 

... but

  • This does not assure me that Logger is actually being introduced and is not null.
  • I do not like when publicly recruited ILogger

So ... what other options do I have? (I use Castle Windsor).

I was supposed to create an interface

 public interface IInitializable<T> { void Initialize(T instance); } public class MyBaseClass : IInitializable<ILogger>, ...could have other IInitializables too... { protected ILogger Logger { get; private set; } public void Initialize(ILogger instance) { Logger = instance; } } 

Then, having an object on my container that automatically calls all IInitializable<T> implementations when building the type ...

But I wonder what other peoples think before I go this way ...

+6
dependency-injection inversion-of-control castle-windsor
source share
3 answers

In your case, I would use property injection.

Entering properties can be switched to mandatory, as described here: http://www.mail-archive.com/ castle-project-users@googlegroups.com /msg08163.html

+1
source share

You are too embarrassed. the recommended and documented ILogger injection template should have a NullLogger.Instance by default (i.e. a null object ) and add an additional dependency to Logger . There is nothing wrong with having a public setter for the registrar. Using a custom IInitializable , like the one you are showing, is likely to only complicate the situation and add no real value.

I will copy the sample from the documentation here for convenience:

 using Castle.Core.Logging; public class CustomerService { private ILogger logger = NullLogger.Instance; public CustomerService() { } public ILogger Logger { get { return logger; } set { logger = value; } } // ... } 

EDIT: It seems the question is to have different registrar implementations depending on the context (which has little to do with the original question). In this case, use utility overrides or handler selectors.

+3
source share

If your base class is independent of ILogger , you must remove the property from the base class. This way you keep the base class constructor clean.

Otherwise, you can create a factory that can create descendants of MyBaseClass . It might look like this:

 public interface IMyBaseClassFactory { MyBaseClass CreateNew<TMyBaseClass>() where TMyBaseClass : MyBaseClass; } 

Now you can create a register that implements IMyBaseClassFactory , which can create new instances and register optional dependencies:

 public MyBaseClassFactoryImpl : IMyBaseClassFactory { public MyBaseClass CreateNew<TMyBaseClass>() { // Call your IoC container to get a descendant. var instance = ServiceLocator.GetInstance<TMyBaseClass>(); // Register missing dependencies instance.Logger = ServiceLocator.GetInstance<ILogger>(); return instance; } } 

Most IoC containers allow you to decorate injection properties with attributes. The advantage of using factory is that your application will remain completely unfamiliar with the IoC map used. As a disadvantage, work remains to be done (creating a factory by entering factory instead of the instance itself and calling factory to create a new instance).

When defining an injectable property, you need to make it read / write. Of course, you do not want anyone to accidentally reset this property afterwards. Without a constructor installation, this is difficult to do with compile-time support. However, checking the runtime is easy:

 private ILogger logger; public ILogger Logger { get { return this.logger; } set { if (this.logger != null) { throw new InvalidOperationException("Logger has already been set."); } this.logger = value; } } 

Hope this helps.

0
source share

All Articles