inversion of control - registertype - ¿Qué significa esto en Prism/Unity: Container.Resolve<ShellPresenter>()
unity property injection (4)
Bueno, no puedo responder por Untiy, pero para Castle Windsor, el registro podría estar en el archivo app.config / web.config. También existe la posibilidad de agregar los parámetros en el xml de configuración.
Esto le permite cambiar la implementación y configuración del objeto sin tener que volver a compilar su aplicación.
(Del archivo StockTraderRIBootstrapper.cs en la aplicación de ejemplo Prism V2 StockTrader)
¿Cuál es la diferencia entre esto?
ShellPresenter presenter = new ShellPresenter();
y esto:
ShellPresenter presenter = Container.Resolve<ShellPresenter>();
- Entiendo que el segundo ejemplo es tratar el contenedor como si fuera una fábrica, caminar hacia él diciendo "Necesito un objeto instanciado de tipo ShellPresenter".
- Pero, ¿qué pasa si, por ejemplo, necesito enviar parámetros, ¿cuál sería el equivalente de "nuevo ShellPresenter (1, verdadero)", etc.?
- Y dado que se debe informar al contenedor sobre el ShellPresenter, esperaba encontrar en algún lugar del proyecto un lugar donde la clase ShellPresenter estuviera registrada en el contenedor, por ejemplo, esperaba
algo como esto:
Container.RegisterType<IShellPresenter, ShellPresenter>();
pero no lo encontré en ninguna parte. Entonces, ¿cómo puede el contenedor conocer estos tipos para poder resolverlos? Reconstruí esto en su propio proyecto y obtengo un error de "Resolución de la dependencia fallida" , ¿dónde necesito registrar esta dependencia entonces?
Cualquier dirección / discusión aquí sería útil.
Respuesta inexplicable:
Entonces, en el bootstrapper, cuando registro el propio Shell:
protected override void ConfigureContainer()
{
Container.RegisterType<IShellView, Shell>();
base.ConfigureContainer();
}
entonces el contenedor puede resolver el tipo ShellPresenter. Entonces, ¿cómo se registra el tipo ShellPresenter cuando registro el tipo Shell ?
La sorprendente respuesta:
Bien, resulta que no tiene que registrar el tipo que está tratando de resolver, pero sí tiene que registrar los tipos de parámetros (interfaz) pasados al constructor del tipo que está tratando de resolver , es decir, desde que inyecto la interfaz IShellView en el constructor de mi ShellPresenter, necesitaba registrar el tipo IShellView y no el tipo IShellPresenter:
public ShellPresenter(IShellView view) ...
Probé esto tratando de resolver el tipo Tester :
Tester tester = Container.Resolve<Tester>();
Mientras yo inyecte SomeClass en su constructor:
public Tester(ISomeClass someClass)
Obtengo errores de dependencia sin resolver hasta que registro SomeClass con el contenedor:
Container.RegisterType<ISomeClass, SomeClass>();
Entonces funciona. Esto es tan sorprendente como educativo. Necesita hundirse. Voy a tomar un café y pensar en esto por un tiempo.
Si alguien puede explicar por qué este es el caso, sería muy apreciado.
En Unity, de hecho hay un conjunto de métodos Container.RegisterType<TFrom, TTo>()
que registra tipos en tiempo de ejecución. Probablemente sea más común hacerlo usando un archivo de configuración XML, pero cualquiera de los dos funciona.
Curiosamente, en Unity no hay un método tipo Container.Resolve<T>(params object[] parameters)
para resolver un tipo con valores de parámetros de constructor específicos. Unity se construye sobre ObjectBuilder, que es la biblioteca del equipo de P&P para realizar la construcción de objetos y el cableado (IIRC se escribió originalmente para ObjectSpaces, pero ahora se ha mejorado significativamente). ObjectBuilder le brinda la capacidad de inyectar dependencias de varias maneras, incluso a través del constructor, por lo que podría decir, por ejemplo, que pasaría una nueva instancia de un tipo del que depende al constructor de un tipo resuelto; Pero ese tipo también tendría que estar registrado. También puede pasar instancias de tipos registrados (una instancia registrada / singleton, etc.). Pero AFAICS no hay manera de simplemente darle un valor para pasar.
Creo que hacer eso iría en contra de la filosofía de la IoC hasta cierto punto, razón por la cual no proporcionan esa facilidad. El contenedor debería, en teoría, poder proporcionarle un gráfico de objetos completo en cualquier circunstancia, de modo que nunca tenga que pasar parámetros, y hacer que sus objetos dependan de parámetros de constructores distintos a las dependencias de objetos inyectables (que el contenedor resolverá). para ti) es visto como mal diseño.
No puedo hablar por Windsor, StructureMap o los otros, lo que puede permitirte hacer esto. Ni siquiera puedo decir categóricamente que Unity no tiene forma de hacerlo ya que soy bastante nuevo en eso, pero IIRC Chris Tavares, que básicamente construyó Unity, se queda aquí de vez en cuando, así que tal vez se pase por ahí y contesta esta :-)
Entiendes lo básico.
Hay sobrecargas para resolver tipos que requieren argumentos de constructor. Alternativamente, siempre puede codificar sus tipos para tener un constructor sin parámetros.
El punto de los contenedores DI es que puede configurarlos para cambiar el tipo que se resuelve para una interfaz en particular sin volver a compilar su software. El ejemplo de código que proporcionó para configurar el proveedor no se puede cambiar en tiempo de ejecución. Es por eso que la mayoría de los inyectores de dependencia le permiten configurarlos en app.config / web.config / algún otro archivo de configuración externo. De esa manera, puede reconfigurar su aplicación para inyectar un tipo diferente sin recompilar, que es el verdadero poder de los marcos DI como Unity.
Si intenta resolver una clase concreta y no ha registrado una instancia o subclase para satisfacerla, entonces Unity construirá una instancia de la clase concreta para usted, resolviendo las dependencias que tenga.
Por lo tanto, cuando solicita ShellPresenter y no lo ha registrado, Unity acaba de crear un ShellPresenter para usted con ShellView como parámetro.