When Josh replied that injecting dependencies with constructor arguments doesn't really solve the problem of dependency creation, I was tempted to reply by enumerating all the .NET dependency injection frameworks that exist for exactly this purpose.
But then I realized that Josh had demonstrated the Service Locator pattern without using any framework. Instead, his article has a ServiceContainer class of about 30 lines. Service Locator has many disadvantages, but apparently it can be quite lightweight!
This then lead me to wonder if the same could be done for creating a dependency injection framework. Ayende has actually already demonstrated that you can create a primitive one in 15 lines, but I was thinking of something that could be used with a more friendly Ninject-esque syntax like this:
var container = new Container(); container.Bind<App, App>(); container.Bind<IFoo, Foo>(); container.Bind<IBar, Bar>(); var app = container.Pull<App>(); app.Run();
As it turns out, implementing a bare bones container which can do that is really not that hard. It also has the advantage that it takes care of the dependencies of the dependencies etcetera, something which Josh's sample doesn't seem to do. (Disclaimer: I didn't really test this for anything but the plain vanilla use case, no error conditions were considered.)
public class Container { private readonly Dictionary<Type, Type> contractToClassMap = new Dictionary<Type, Type>(); private readonly Dictionary<Type, object> contractToInstanceMap = new Dictionary<Type, object>(); public void Bind<TContract, TClass>() where TClass : class, TContract { this.contractToClassMap[typeof(TContract)] = typeof(TClass); } public TContract Pull<TContract>() { return (TContract)Pull(typeof(TContract)); } public object Pull(Type contract) { object instance; this.contractToInstanceMap.TryGetValue(contract, out instance); if (instance == null) { var constructor = contractToClassMap[contract].GetConstructors()[0]; var args = from parameter in constructor.GetParameters() select Pull(parameter.ParameterType); instance = constructor.Invoke(args.ToArray()); this.contractToInstanceMap[contract] = instance; } return instance; } }