Inversión de control es un concepto general donde el flujo de control normal se "invierte" de alguna manera.
Por flujo "normal", me refiero a un flujo de aplicación por lotes tradicional: el código se ejecuta de principio a fin, crea recursos, solicita datos y proporciona resultados. El flujo de control es dictado por la aplicación en sí misma, invocando bibliotecas e instalaciones del sistema según sea necesario. Cualquier inversión de esto, donde las bibliotecas en lugar de la aplicación (usando estos términos de manera un tanto vaga) impulsa el flujo de control, es en cierto sentido una inversión de control.
Uno de los ejemplos más comunes de IoC es un bucle de eventos. En un bucle de eventos, el kit de herramientas de la GUI (o el sistema operativo) está en control y vuelve a llamar a su aplicación para manejar eventos y procesar la entrada. El flujo normal: solicitud de entrada & procesándolo: se invierte para que el procesador de entrada maneje la aplicación, en lugar de hacerlo al revés.
La inyección de dependencia es un uso específico de Inversión de control, donde la inversión de control se aplica a la selección y asignación de dependencias. En lugar de tener un componente que ejemplifique los subcomponentes que requiere, el código de creación (ya sea el código de la aplicación, manualmente o el contenedor DI) crea una instancia de los subcomponentes necesarios y los inyecta en el componente.