If you don't need anything fancy, a DI container can be really short:
public class Container
{
   private readonly Dictionary<Type,Func<Container,object>> factories;
   private readonly Dictionary<Type,object> cache;
   public Container()
   {
       this.factories = new Dictionary<Type,Func<Container,object>>();
       this.cache = new Dictionary<Type,object>();
   }
   public void Register<TContract>(Func<Container,TContract> factory)
   {
       // wrap in lambda which returns object instead of TContract
       factories[typeof(TContract)] = c => factory(c);
   }
   public TContract Get<TContract>()
   {
       var contract = typeof(TContract);
       if (!cache.ContainsKey(contract))
       {
           this.cache[contract] = this.factories[contract](this);
       }
       return (TContract)this.cache[contract];
   }
}
Which you would use like this:
var container = new Container();
container.Register<ICar>(c => new Car(
    c.Get<IEngine>(), c.Get<IWheel>()));
container.Register<IWheel>(c => new Wheel());
container.Register<IEngine>(c => new Engine());
var car = container.Get<ICar>();
Even more minimalistic would be to do dependency injection without a container:
IWheel wheel = new Wheel();
IEngine engine = new Engine();
ICar car = new Car(engine, wheel);
However, for complex object graphs it can quickly get complicated to maintain the correct construction order during refactorings. The container doesn't have this problem.