I am a big fan of dependency injection and inversion of control. I strive to use these techniques in almost every project I am involved with. Usually when I develop the project from the ground, the whole design is ready for automatic types scanning and auto wiring. So it is very easy to wire them up using a short piece of code. All the examples in this post will be using Autofac - the addictive IoC container.
But sometimes, I need to prevent some classes from being registered, for example, the instance need to be created in run time with specific context parameters. In this case I use the opt-out, i.e. register all the types except those having a custom attribute:
In order to use the attribute in this syntax, I am using an extension method:
public IContainer Initialize() { var builder = new ContainerBuilder(); builder.RegisterAssemblyTypes(GetType().Assembly).AsImplementedInterfaces(); return builder.Build(); }
But sometimes, I need to prevent some classes from being registered, for example, the instance need to be created in run time with specific context parameters. In this case I use the opt-out, i.e. register all the types except those having a custom attribute:
[AttributeUsage(AttributeTargets.Class)] public class DontRegisterInContainerAttribute : Attribute { } public IContainer Initialize() { var builder = new ContainerBuilder(); builder.RegisterAssemblyTypes(GetType().Assembly) .Where(t => !t.HasAttribute<DontRegisterInContainerAttribute>()) .AsImplementedInterfaces(); return builder.Build(); }
public static class TypeExtensions { public static bool HasAttribute<T>(this Type @this) { return @this.GetCustomAttributes(typeof (T), false).Any(); } }
In some projects, when I am modifying existing code, which is not "IoC-ready", I need to register only a few classes. Hopefully their number will increase in the future. But currently what I am actually want is to type the container: register only these classes, without actually listing them or assume they reside in some namespace or have something in their name. In such cases I use the opposite:
public IContainer Initialize() { var builder = new ContainerBuilder(); builder.RegisterAssemblyTypes(GetType().Assembly) .Where(t => t.HasAttribute<RegisterInContainerAttribute>()) .AsImplementedInterfaces(); return builder.Build(); }
With the corresponding custom attribute:
[AttributeUsage(AttributeTargets.Class)] public class RegisterInContainerAttribute : Attribute { }
Using this method of registering only types marked with the attribute also makes the code clearer to co-workers, who might look up for usages of the attribute and find out what classes are registered in the container. In case they are not familiar with Agent Mulder Resharper plugin.