unity ioc injection framework dependency c# dependency-injection unity-container ioc-container ninject

injection - ¿Cómo se comparan los principales marcos C#DI/IoC?



unity dependency injection (7)

A riesgo de entrar en el territorio de la guerra santa, ¿cuáles son las fortalezas y debilidades de estos marcos populares de DI / IoC, y podría uno fácilmente ser considerado el mejor? ..:

  • Ninject
  • Unidad
  • Castillo.Windsor
  • Autofac
  • Mapa de estructura

¿Hay otros marcos de trabajo DI / IoC para C # que no haya enumerado aquí?

En el contexto de mi caso de uso, estoy creando una aplicación WPF cliente y una infraestructura de servicios WCF / SQL, la facilidad de uso (especialmente en términos de sintaxis clara y concisa), documentación coherente, buen soporte de la comunidad y rendimiento son todos factores importantes en mi eleccion

Actualizar:

Los recursos y las preguntas duplicadas que se citan parecen estar desactualizados, ¿puede alguien con conocimiento de todos estos marcos presentar y proporcionar una visión real?

Me doy cuenta de que es probable que la mayoría de las opiniones sobre este tema estén sesgadas, pero espero que alguien se haya tomado el tiempo de estudiar todos estos marcos y tenga al menos una comparación generalmente objetiva.

Estoy bastante dispuesto a hacer mis propias investigaciones si esto no se ha hecho antes, pero asumí que esto era algo que al menos algunas personas ya habían hecho.

Segunda actualización:

Si tiene experiencia con más de un contenedor DI / IoC, clasifique y resuma los pros y los contras de estos, gracias. Este no es un ejercicio para descubrir todos los pequeños contenedores oscuros que la gente ha hecho, estoy buscando comparaciones entre los marcos populares (y activos).


Bueno, después de mirar alrededor la mejor comparación que he encontrado hasta ahora es:

Fue una encuesta realizada en marzo de 2010.

Un punto de interés para mí es que a las personas que han utilizado un marco de DI / IoC y les ha gustado / disgustado, StructureMap parece sobresalir.

También de la encuesta, parece que Castle.Windsor y StructureMap parecen ser los más favorecidos.

Curiosamente, Unity y Spring.Net parecen ser las opciones populares que más a Spring.Net no les gustan. (Estaba considerando a Unity por pereza (y la insignia / soporte de Microsoft), pero ahora estaré observando más de cerca a Castle Windsor y StructureMap).

Por supuesto, esto probablemente (?) No se aplica a Unity 2.0, que se lanzó en mayo de 2010.

Esperemos que alguien más pueda proporcionar una comparación basada en la experiencia directa.


En realidad hay toneladas de marcos de IoC. Parece que cada programador intenta escribir uno en algún momento de su carrera. Tal vez no para publicarlo, sino para aprender el funcionamiento interno.

Personalmente prefiero autofac ya que es bastante flexible y tengo la sintaxis que me conviene (aunque realmente odio que todos los métodos de registro sean métodos de extensión).

Algunos otros marcos:


Me encontré con otra comparison rendimiento (última actualización 10 de abril de 2014). Se compara lo siguiente:

Aquí hay un breve resumen de la publicación:

Conclusión

Ninject es definitivamente el contenedor más lento.

MEF, LinFu y Spring.NET son más rápidos que Ninject, pero siguen siendo bastante lentos. AutoFac, Catel y Windsor son los siguientes, seguidos de StructureMap, Unity y LightCore. Una desventaja de Spring.NET es que solo se puede configurar con XML.

SimpleInjector, Hiro, Funq, Munq y Dynamo ofrecen el mejor rendimiento, son extremadamente rápidos. ¡Dales una oportunidad!

Especialmente Simple Injector parece ser una buena opción. Es muy rápido, tiene una buena documentación y también admite escenarios avanzados como intercepción y decoradores genéricos.

También puede intentar usar la Biblioteca de Selector de Servicios Comunes y, con suerte, probar múltiples opciones y ver qué funciona mejor para usted.

Alguna información sobre la Biblioteca de Selector de Servicios Comunes del sitio:

La biblioteca proporciona una abstracción sobre contenedores de IoC y localizadores de servicio. El uso de la biblioteca permite que una aplicación acceda indirectamente a las capacidades sin depender de referencias duras. La esperanza es que al usar esta biblioteca, las aplicaciones y los marcos de terceros puedan comenzar a aprovechar IoC / Service Location sin atarse a una implementación específica.

Actualizar

13.09.2011: Funq y Munq se agregaron a la lista de participantes. Los gráficos también se actualizaron y Spring.NET se eliminó debido a su bajo rendimiento.

04.11.2011: "agregó Simple Injector , el rendimiento es el mejor de todos los participantes".


Mira para una comparación de net-ioc-frameworks en el código de google, incluyendo linfu y spring.net que no están en tu lista mientras escribo este texto.

Trabajé con spring.net: tiene muchas características (AOP, bibliotecas, docu, ...) y hay mucha experiencia con él en dotnet y java-world. Las características están modularizadas para que no tenga que tomar todas las características. Las características son abstracciones de problemas comunes como la base de datos de datos, el registro y la acción. sin embargo, es difícil hacer y depurar la configuración IoC.

Por lo que he leído hasta ahora: si tuviera que elegir para un proyecto pequeño o mediano, usaría ninject ya que ioc-configuration está hecho y se puede depurar en c #. Pero no he trabajado con eso todavía. para el sistema modular grande me quedaría con spring.net debido a las bibliotecas de abstracción.


Si bien una respuesta completa a esta pregunta ocupa cientos de páginas de mi libro , aquí hay una tabla de comparación rápida en la que todavía estoy trabajando:



Descargo de responsabilidad: desde principios de 2015, hay una gran comparación de las características de IoC Container de Jimmy Bogard , aquí hay un resumen:

Contenedores Comparados:

  • Autofac
  • Ninject
  • Inyector simple
  • Mapa de estructura
  • Unidad
  • Windsor

El escenario es el siguiente: tengo una interfaz, IMediator, en la que puedo enviar una solicitud / respuesta única o una notificación a varios destinatarios:

public interface IMediator { TResponse Send<TResponse>(IRequest<TResponse> request); Task<TResponse> SendAsync<TResponse>(IAsyncRequest<TResponse> request); void Publish<TNotification>(TNotification notification) where TNotification : INotification; Task PublishAsync<TNotification>(TNotification notification) where TNotification : IAsyncNotification; }

Luego creé un conjunto base de solicitudes / respuestas / notificaciones:

public class Ping : IRequest<Pong> { public string Message { get; set; } } public class Pong { public string Message { get; set; } } public class PingAsync : IAsyncRequest<Pong> { public string Message { get; set; } } public class Pinged : INotification { } public class PingedAsync : IAsyncNotification { }

Me interesaba ver algunas cosas con respecto al soporte de contenedores para genéricos:

  • Configuración para genéricos abiertos (registro de IRequestHandler <,> fácilmente)
  • Configuración para múltiples registros de genéricos abiertos (dos o más INotificationHandlers)

Configuración para la varianza genérica (registro de controladores para INotification base / creación de tuberías de solicitud) Mis controladores son bastante sencillos, simplemente se envían a la consola:

public class PingHandler : IRequestHandler<Ping, Pong> { /* Impl */ } public class PingAsyncHandler : IAsyncRequestHandler<PingAsync, Pong> { /* Impl */ } public class PingedHandler : INotificationHandler<Pinged> { /* Impl */ } public class PingedAlsoHandler : INotificationHandler<Pinged> { /* Impl */ } public class GenericHandler : INotificationHandler<INotification> { /* Impl */ } public class PingedAsyncHandler : IAsyncNotificationHandler<PingedAsync> { /* Impl */ } public class PingedAlsoAsyncHandler : IAsyncNotificationHandler<PingedAsync> { /* Impl */ }

Autofac

var builder = new ContainerBuilder(); builder.RegisterSource(new ContravariantRegistrationSource()); builder.RegisterAssemblyTypes(typeof (IMediator).Assembly).AsImplementedInterfaces(); builder.RegisterAssemblyTypes(typeof (Ping).Assembly).AsImplementedInterfaces();

  • Genéricos abiertos: sí, implícitamente
  • Múltiples genéricos abiertos: sí, implícitamente.
  • Contravarianza genérica: sí, explícitamente

Ninject

var kernel = new StandardKernel(); kernel.Components.Add<IBindingResolver, ContravariantBindingResolver>(); kernel.Bind(scan => scan.FromAssemblyContaining<IMediator>() .SelectAllClasses() .BindDefaultInterface()); kernel.Bind(scan => scan.FromAssemblyContaining<Ping>() .SelectAllClasses() .BindAllInterfaces()); kernel.Bind<TextWriter>().ToConstant(Console.Out);

  • Genéricos abiertos: sí, implícitamente
  • Múltiples genéricos abiertos: sí, implícitamente.
  • Contravarianza genérica: sí, con extensiones construidas por el usuario

Inyector simple

var container = new Container(); var assemblies = GetAssemblies().ToArray(); container.Register<IMediator, Mediator>(); container.Register(typeof(IRequestHandler<,>), assemblies); container.Register(typeof(IAsyncRequestHandler<,>), assemblies); container.RegisterCollection(typeof(INotificationHandler<>), assemblies); container.RegisterCollection(typeof(IAsyncNotificationHandler<>), assemblies);

  • Genéricos abiertos: sí, explícitamente
  • Múltiples genéricos abiertos: sí, explícitamente
  • Contravarianza genérica: sí, implícitamente (con actualización 3.0)

Mapa de estructura

var container = new Container(cfg => { cfg.Scan(scanner => { scanner.AssemblyContainingType<Ping>(); scanner.AssemblyContainingType<IMediator>(); scanner.WithDefaultConventions(); scanner.AddAllTypesOf(typeof(IRequestHandler<,>)); scanner.AddAllTypesOf(typeof(IAsyncRequestHandler<,>)); scanner.AddAllTypesOf(typeof(INotificationHandler<>)); scanner.AddAllTypesOf(typeof(IAsyncNotificationHandler<>)); }); });

  • Genéricos abiertos: sí, explícitamente
  • Múltiples genéricos abiertos: sí, explícitamente
  • Contravarianza genérica: sí, implícitamente

Unidad

container.RegisterTypes(AllClasses.FromAssemblies(typeof(Ping).Assembly), WithMappings.FromAllInterfaces, GetName, GetLifetimeManager); /* later down */ static bool IsNotificationHandler(Type type) { return type.GetInterfaces().Any(x => x.IsGenericType && (x.GetGenericTypeDefinition() == typeof(INotificationHandler<>) || x.GetGenericTypeDefinition() == typeof(IAsyncNotificationHandler<>))); } static LifetimeManager GetLifetimeManager(Type type) { return IsNotificationHandler(type) ? new ContainerControlledLifetimeManager() : null; } static string GetName(Type type) { return IsNotificationHandler(type) ? string.Format("HandlerFor" + type.Name) : string.Empty; }

  • Genéricos abiertos: sí, implícitamente
  • Múltiples genéricos abiertos: sí, con extensión construida por el usuario
  • Contravarianza genérica: derp

Windsor

var container = new WindsorContainer(); container.Register(Classes.FromAssemblyContaining<IMediator>().Pick().WithServiceAllInterfaces()); container.Register(Classes.FromAssemblyContaining<Ping>().Pick().WithServiceAllInterfaces()); container.Kernel.AddHandlersFilter(new ContravariantFilter());

  • Genéricos abiertos: sí, implícitamente
  • Múltiples genéricos abiertos: sí, implícitamente.
  • Contravarianza genérica: sí, con extensión construida por el usuario