Cómo escribir bibliotecas sin obligar a los usuarios a usar el contenedor IOC de la biblioteca

a pregunta corta es: dada una biblioteca warrants usando un contenedor IOC particular para sus componentes internos, cuando una aplicación consume esa biblioteca, dada la aplicación warrants usando un contenedor IOC para conectar sus dependencias, dado que los dos contenedores son diferentes, ¿cómo pueden jugar bien juntos?

El escenario es que la aplicación tiene clases definidas que dependen de los tipos de la biblioteca. Entonces, cuando el contenedor de la aplicación intenta crear una clase de este tipo, necesita saber cómo resolver el tipo que vive en la biblioteca.

Aquí está la larga pregunta:

Esta pregunta parece haber sido formulada de diferentes formas antes en SO, pero parece que no puedo encontrar la respuesta que necesito, así que voy a intentarlo con un ejemplo hipotético _sobre_simplificado_ concreto. Queremos escribir una biblioteca para el registro que los usuarios puedan incluir como un paquete en su solución para obtener la funcionalidad de registro de fábrica. Las interfaces públicas que expone la biblioteca son ..

public interface ILogger {}

public interface ITarget {}

as implementaciones de @Concrete son

internal class Logger: ILogger { public Logger(ITarget target) {}}

internal class FileTarget : ITarget {}

os requisitos son @ si el usuario incluye nuestro paquete y define una clase con una propiedad de tipoILogger o tiene un argumento ctor de tipoILogger entonces nuestra biblioteca es responsable de inyectar una implementación concreta para esa interfaz en la clase definida por el usuario. Por defecto, ese registrador inyectado irá al sistema de archivos para iniciar sesión porque la implementación predeterminada de unITarget inyectado en elILogger implementación es unaFileTarget por nuestra biblioteca.

Si el usuario decide escribir una clase implementando laITarget interfaz, entonces nuestra biblioteca lo usará para inyectar en elLogger clase y no usar su @ predeterminaFileTarget implementación.

SO lo que deseo demostrar es que aquí hay una dependencia bidireccional.

Nuestra biblioteca depende de los ensamblajes del usuario, ya que necesita escanear los ensamblajes del usuario para cargar cualquier punto de extensión (es decir, unaITarget implementación) e inyectarlos en sus propios objetos antes de cualquier implementación predeterminada.

os ensamblados del usuario dependen de la biblioteca, ya que si el usuario elige definir una clase con unILogger como una dependencia, entonces ese objeto de usuario debería obtener una referencia concreta a esa interfaz proporcionada en tiempo de ejecución por nuestra biblioteca.

La solución fácil es si el usuario y nuestra biblioteca están utilizando el mismo contenedor IOC, entonces el problema está resuelto. Pero esta es una suposición fuerte. Lo que deseo hacer es

Utilice un contenedor IOC con la biblioteca que mejor satisfaga los requisitos de la biblioteca, en mi caso es Ninject.En el tiempo de ejecución, de alguna manera, se proporciona un mecanismo para que el usuario llame a través de alguna API a mi biblioteca que garantizará que Ninject se active y escanee los ensamblajes del usuario, y conecte todo teniendo en cuenta todos los puntos de extensión.

asta ahora todo bien, es perfectamente posible, pero aquí viene la parte difícil.

si el usuario también está usando Ninject, el problema se resuelve automáticamente, ya que Ninject ya sabe cómo resolver las interfaces que viven en nuestra biblioteca. Pero, ¿qué sucede si el usuario decide usar su elección de contenedor IOC?

asi quiero definir algún tipo de funcionalidad de contenedor secundario en la biblioteca con una interfaz como esta

public interface IDependencyResolvingModule { T Get<T>(); []T GetAll<T>(); }

y proporcionar una implementación que utilice la opción de contenedor de nuestra biblioteca (es decir, Ninect) para resolver el tipo solicitado en los dos métodos definidos anteriormente.

Quiero que el contenedor IOC del usuario tenga alguna funcionalidad donde si no puede resolver una dependencia (es decir, unILogger), debe engancharse a laIDependencyResolvingModule implementación y solicite la dependencia.

De esta manera, nuestra biblioteca puede usar su elección de Contenedor IOC, y el código del usuario tiene una manera de resolver las dependencias de las que su contenedor IOC no tiene idea. ¿No funcionaría esta solución si los contenedores IOC existen de alguna manera cómo se proporciona la funcionalidad para registrar instancias singleton de cualquierIDependencyResolverModules encontrado en ensamblajes en el directorio del ensamblaje en ejecución y cuando no pueden resolver un tipo, pregunte a cualquiera de los módulos singleton?

Pero salvo una solución que requiera que cada otro contenedor de COI se acomode, ¿de qué otra manera se puede resolver? Entonces, el problema en pocas líneas es que, cuando un ensamblado de un tercero elige usar un contenedor IOC para sus componentes internos, ¿cuál es una solución fácil para que esta biblioteca pueda simplemente proporcionar un mecanismo para que un contenedor IOC que se encuentre afuera para enganchar y resolver dependencias? que viven en la biblioteca.