2012-09-05 24 views
15

Tengo un proyecto donde se usa el Ninject como contenedor IoC. Mi preocupación es que una gran cantidad de clases tiene este tipo de constructores:Lazy Dependency Injection

[Inject] 
public HomeController(
    UserManager userManager, RoleManager roleManager, BlahblahManager blahblahManager) { 
    _userManager = userManager; 
    _roleManager = roleManager; 
    _blahblahManager = blahblahManager; 
} 

¿Qué pasa si no quiero tener todas las instancias de estas clases a la vez?

El camino, cuando todas estas clases están envueltas por Lazy<T> y pasan al constructor no es exactamente lo que necesito. Las instancias T aún no se han creado, pero las instancias Lazy<T> ya están almacenadas en la memoria.

Mi colega me sugiere utilizar el patrón Factory para tener control sobre todas las instancias, pero no estoy seguro de que IoC tenga un error de diseño tan grande.

¿Hay alguna solución para esta situación o IoC realmente tiene un gran defecto en su diseño? Tal vez debería usar otro contenedor IoC?

¿Alguna sugerencia?

+0

¿Cuál es realmente su problema? ¿Por qué no quieres estas instancias? –

+2

Es posible que desee UserManager durante el trabajo del controlador, pero RoleManager no es necesario y viceversa. Si hablas de las instancias de Lazy , entonces no es un gran problema tenerlas en la memoria, pero, ¿es esta la única manera? – xwrs

+1

¿Por qué es un gran problema para 'UserManager' y' RoleManager'? Sus constructores no deberían hacer un trabajo pesado de todos modos. –

Respuesta

36

Me parece que estás haciendo premature optimization: no lo hagas.

Los constructores de sus servicios deben hacer nothing more que almacenar las dependencias que toma en campos privados. En ese caso, la creación de tal objeto es realmente liviana. No olvides que la creación de objetos en .NET es realmente rápida. En la mayoría de los casos, desde una perspectiva de rendimiento, simplemente no importa si esas dependencias se inyectan o no. Especialmente cuando se compara con la cantidad de objetos que el resto de la aplicación (y los marcos que usa) están escupiendo. El costo real es cuando comienzas a usar servicios web, bases de datos o el sistema de archivos (o E/S en general), porque causan un retraso mucho mayor.

Si la creación es muy caro, que normalmente debe ocultar la creación detrás de un Virtual Proxy en lugar de inyectar un Lazy<T> de todos los consumidores, ya que esto permite que el código de aplicación común para permanecer ajeno al hecho de que no existe un mecanismo para retrasar la creación (Tanto el código de la aplicación como el código de prueba se vuelven más complejos cuando haces esto).

El capítulo 6 de Dependency Injection in .NET, second edition contiene una discusión más detallada acerca de los Proxies lazy y virtuales.

Sin embargo, un Lazy<T> solo consume 20 bytes de memoria (y otro 24 bytes por su envuelta Func<T>, suponiendo un proceso de 32 bits), y la creación de una instancia Lazy<T> es prácticamente libre. Por lo tanto, no hay necesidad de preocuparse por esto, excepto cuando se encuentre en un entorno con restricciones de memoria muy ajustadas.

Y si el consumo de memoria es un problema, intente registrar servicios de por vida que sean más grandes que transitorios. Puede hacer una solicitud por solicitud web o singleton. Incluso diría que cuando estás en un entorno en el que crear un objeto nuevo es un problema, probablemente solo deberías usar servicios singleton (pero es poco probable que estés trabajando en ese entorno, ya que estás construyendo una aplicación web). .

Tenga en cuenta que Ninject es una de las bibliotecas DI más lentas para .NET. Si eso te preocupa, switch to a faster container. Algunos contenedores tienen un rendimiento que está cerca de actualizar gráficos de objetos a mano. pero, por supuesto, haz un perfil de esto, muchos desarrolladores cambian de biblioteca DI por las razones equivocadas.

Tenga en cuenta que el uso de Lazy<T> como dependencia es un leaky abstraction (una violación del Dependency Inversion Principle). Por favor, lea this answer para obtener más información.

+0

Gracias. Hiciste mi entendimiento de la situación más claro. – xwrs

+0

No creo que sea una optimización prematura, con este argumento parece que nunca hay necesidad de Lazy, la creación de un objeto no es pesada, pero no se sabe cuántos objetos está creando en su constructor. Y abriendo un recurso remoto que no se puede usar. –

0

Nueva

Steven tiene razón cuando dice que esto se parece a la optimización prematura. La construcción de estos objetos es muy rápida y generalmente nunca es el cuello de botella.

Sin embargo, el uso de Lazy para expresar una dependencia que no necesita de inmediato es un patrón común en los marcos de Dependency Injection. Actofac es uno de esos contenedores que ha incorporado soporte para various wrapping types. Estoy seguro de que también hay una extensión para Ninject, tal vez eche un vistazo a este, Ninject Lazy.

+1

El hecho de que los contenedores DI tengan soporte para Lazy , no hace que sea correcto permitir que el código de la aplicación dependa de una dependencia de Lazy . Muchos contenedores DI admiten funciones que no promueven las mejores prácticas. Desde una perspectiva de Inyección de Dependencia, Lazy es una abstracción con goteras. Por favor, lea [esto] (https://stackoverflow.com/a/21724609/264697) para obtener una explicación sobre por qué Lazy tiene fugas. – Steven

Cuestiones relacionadas