Как сравнить основные каркасы С# DI/IoC?

Из-за риска выхода на святую военную территорию, Каковы сильные и слабые стороны этих популярных рамок DI/IoC, и можно ли считать их лучшими?..

  • Ninject
  • Единство
  • Castle.Windsor
  • Autofac
  • StructureMap

Существуют ли какие-либо другие рамки DI/IoC для С#, которые я не перечислял здесь?

В контексте моего варианта использования я создаю клиентское приложение WPF и инфраструктуру служб WCF/SQL, простоту использования (особенно с точки зрения четкого и сжатого синтаксиса), согласованную документацию, хорошую поддержку сообщества и производительность все важные факторы в моем выборе.

Обновление:

Ресурсы и повторяющиеся вопросы, по-видимому, устарели, может ли кто-то, кто знает все эти рамки, выступить и дать реальную информацию?

Я понимаю, что большинство мнений по этому вопросу, вероятно, будут предвзятыми, но я надеюсь, что кто-то нашел время для изучения всех этих структур и, по крайней мере, в целом объективного сравнения.

Я вполне готов сделать свои собственные расследования, если это не было сделано раньше, но я предположил, что это было по крайней мере несколько человек уже сделали.

Второе обновление:

Если у вас есть опыт работы с более чем одним контейнером DI/IoC, пожалуйста, оцените и обобщите плюсы и минусы тех, спасибо. Это не упражнение в обнаружении всех неясных маленьких контейнеров, которые люди сделали, я ищу сравнения между популярными (и активными) фреймами.

Ответ 1

Несмотря на то, что исчерпывающий ответ на этот вопрос занимает сотни страниц моей книги, приведу краткую сравнительную таблицу, над которой я все еще работаю:

A table explaining difference between several DICs

Ответ 2

Я наткнулся на другое исполнение comparison (последнее обновление 10 апреля 2014 года). Он сравнивает следующее:

Вот краткое резюме из сообщения:

Заключение

Ninject определенно является самым медленным контейнером.

MEF, LinFu и Spring.NET быстрее, чем Ninject, но все же довольно медленный. Далее следуют AutoFac, Catel и Windsor, а затем StructureMap, Unity и LightCore. Недостатком Spring.NET является то, что может быть только с XML.

SimpleInjector, Hiro, Funq, Munq и Dynamo предлагают лучшие производительность, они чрезвычайно быстры. Попробуйте!

Особенно простой инжектор кажется хорошим выбором. Это очень быстро, хорошо документацию, а также поддерживает расширенные сценарии, такие как перехват и общие декораторы.

Вы также можете попробовать использовать общую селектор услуг и, надеюсь, попробуйте несколько опций и посмотрите, что лучше всего подходит вам.

Некоторая информация о библиотеке выбора общих служб с сайта:

Библиотека обеспечивает абстракцию над контейнерами IoC и сервисом локаторы. Использование библиотеки позволяет приложению косвенно обращаться возможности, не полагающиеся на жесткие ссылки. Надеемся, что используя эту библиотеку, сторонние приложения и фреймворки могут начинаться использовать местоположение IoC/Service без привязки к конкретной реализации.

Update

13.09.2011: Funq и Munq были добавлен в список конкурсантов. Карты также были обновлены, а Spring.NET был удален из-за низкой производительности.

04.11.2011: "добавлен Простой инжектор, производительность - лучшая из всех участников ".

Ответ 3

Просто прочитайте эту замечательную . Net, сравнительный блог от Филиппа Мата.

Он проводит некоторые сравнительные тесты производительности;

Он рекомендует Autofac, поскольку он маленький, быстрый и простой в использовании... Согласен. Похоже, что Unity и Ninject являются самыми медленными в его тестах.

Ответ 4

Отказ от ответственности:. С начала 2015 года существует большое сравнение функций IoC Container из Jimmy Богард, вот резюме:

Сравнение контейнеров:

  • Autofac
  • Ninject
  • Простой инжектор
  • StructureMap
  • Unity
  • Windsor

Сценарий таков: у меня есть интерфейс, IMediator, в котором я могу отправить один запрос/ответ или уведомление нескольким получателям:

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; 
}

Затем я создал базовый набор запросов/ответов/уведомлений:

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 { }

Мне было интересно посмотреть на некоторые вещи в отношении поддержки контейнеров для дженериков:

  • Настройка открытых дженериков (регистрация IRequestHandler <, > легко)
  • Настройка для нескольких регистраций открытых дженериков (двух или более INotificationHandlers)

Настройка общей дисперсии (регистрация обработчиков для базовых инициализации/создание запросов) Мои обработчики довольно просты, они просто выводятся на консоль:

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();
  • Открытые дженерики: да, неявно
  • Несколько открытых дженериков: да, неявно
  • Общая контравариантность: да, явно

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);
  • Открытые дженерики: да, неявно
  • Несколько открытых дженериков: да, неявно
  • Общая контравариантность: да, с пользовательскими расширениями

Простой инжектор

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);
  • Открытые дженерики: да, явно
  • Несколько открытых дженериков: да, явно
  • Общая контравариантность: да, неявно (с обновлением 3.0)

StructureMap

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<>));
    });
});
  • Открытые дженерики: да, явно
  • Несколько открытых дженериков: да, явно
  • Общая контравариантность: да, неявно

Unity

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;
}
  • Открытые дженерики: да, неявно
  • Несколько открытых дженериков: да, с пользовательским расширением
  • Общая контравариантность: derp

Виндзор

var container = new WindsorContainer();
container.Register(Classes.FromAssemblyContaining<IMediator>().Pick().WithServiceAllInterfaces());
container.Register(Classes.FromAssemblyContaining<Ping>().Pick().WithServiceAllInterfaces());
container.Kernel.AddHandlersFilter(new ContravariantFilter());
  • Открытые дженерики: да, неявно
  • Несколько открытых дженериков: да, неявно
  • Общая контравариантность: да, с пользовательским расширением

Ответ 5

На самом деле существует множество платформ IoC. Кажется, что каждый программист пытается написать один в какой-то момент своей карьеры. Может быть, не публиковать его, а изучить внутреннюю работу.

Лично я предпочитаю autofac, поскольку он достаточно гибкий и имеет синтаксис, который мне подходит (хотя я действительно ненавижу, что все методы регистров являются методами расширения).

Некоторые другие рамки:

Ответ 6

Хорошо, посмотрев на лучшее сравнение, которое я нашел до сих пор:

Это был опрос, проведенный в марте 2010 года.

Одна из интересных для меня точек зрения заключается в том, что люди, которые использовали схему DI/IoC и любили/не любили, StructureMap, похоже, выходит сверху.

Также из опроса кажется, что Castle.Windsor и StructureMap, по-видимому, наиболее благоприятны.

Интересно, что Unity и Spring.Net кажутся популярными опциями, которые в большинстве случаев не нравятся. (Я рассматривал Unity из лени (и значок/поддержка Microsoft), но теперь я буду более внимательно смотреть на Castle Windsor и StructureMap.)

Конечно, это возможно (?) не относится к Unity 2.0, выпущенному в мае 2010 года.

Надеемся, что кто-то другой может предоставить сравнение, основанное на непосредственном опыте.

Ответ 7

См. сравнение net-ioc-frameworks в коде google, включая linfu и spring.net, которых нет в вашем списке, в то время как Я пишу этот текст.

Я работал с spring.net: у него много функций (aop, libraries, document,...), и в dotnet и java-мире есть много опыта. Эти функции являются модульными, поэтому вам не нужно принимать все функции. Это абстракции общих проблем, таких как databaseabstraction, loggingabstraction. однако затруднительно выполнить и отладить конфигурацию IoC.

Из того, что я прочитал до сих пор: если мне пришлось выбирать для небольшого или среднего проекта, я бы использовал ninject, поскольку ioc-конфигурация выполняется и отлаживается в С#. Но я еще не работал с ним. для большой модульной системы я бы остался с spring.net из-за библиотек абстракции.