Как сравниваются основные платформы C # DI / IoC? [закрыто]

308

С риском вступления на территорию священной войны, каковы сильные и слабые стороны этих популярных систем DI / IoC, и можно ли их легко назвать лучшей? ..:

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

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

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

Обновить:

Упомянутые ресурсы и повторяющиеся вопросы, по-видимому, устарели. Может ли кто-нибудь, обладающий знаниями обо всех этих рамках, выступить с реальными знаниями?

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

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

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

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

ocodo
источник
1
Тот же вопрос, что и в [Ninject vs Unity for DI] ( stackoverflow.com/questions/1054801/ninject-vs-unity-for-di ), но это может быть время для продолжения.
Мэтью Флэшен
2
возможный дубликат [Сравнение Castle Windsor, Unity и StructureMap] ( stackoverflow.com/questions/2216684/… )
Маурисио Шеффер
@slomojo: Возможно, дубликат. stackoverflow.com/questions/4509458/ioc-comparisions-closed . Также есть ссылка, которая показывает популярность IoC в ответе. Посмотри на это.
Динеш,
@chibacity - я использовал его в ... 4 проектах, первые два были действительно простыми, никаких проблем, вторые два, Unity вызвал у нас так много проблем, когда дело дошло до внедрения конструктора, удобства сопровождения, читаемости. В итоге мы вырвали Unity из обоих и заменили его на StructureMap, внедрение конструктора было очень простым, конфигурация была чистой и удобной в обслуживании. В свое личное время я играл с AutoFac, но я нахожу это неудобным, мне нужна некоторая документация, чтобы понять это лучше. Остальное я могу комментировать только то, что прочитал.
Фил
Одна из проблем, с которой мы столкнулись, была с SSRS, она молча проваливалась и перешагивала код, который мы не могли понять, почему он терпел неудачу, исключение было неоднозначным. Мы потратили неделю на написание обходных решений, чтобы все заработало. В конце концов, когда мы перешли на StructureMap, у нас была еще одна попытка, и через несколько минут, используя ObjectFactory.WhatDoIHave (), мы узнали, что IoC создавался до того, как сборки были загружены в AppDomain, поэтому интерфейсы никогда не регистрировались в конкретном приложении. типы.
Фил

Ответы:

225

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

Таблица, объясняющая разницу между несколькими DIC

Марк Симанн
источник
40
Я прочитал MEAP вашей книги и удивлялся, почему вы оставили Ninject вне его?
Мартин Оуэн
2
Частичный ответ можно найти здесь: manning-sandbox.com/thread.jspa?threadID=38943
Марк
25
@Mark, спасибо за это, надеюсь, ваш ответ может включать в себя Ninject (важно, не только из-за нового обмана, окружающего его, но и из-за использования новых языковых функций.)
ocodo
3
Хотя Ninject похож на AutoFac по многим параметрам, он используется командой NUGET, и самый популярный загруженный контейнер IOC достается. Я был разочарован тем, что этого не было в «Инъекции зависимостей» Марка в .NET. Если есть второе издание о том, как выглядит индустрия, надеюсь, оно попадет в книгу. Я либо сталкиваюсь с Unity, MEF (а не с реальным DI), Ninject или StructurMap, я просто еще не получил контракт или удаленный концерт, который использует spring.net или autofac и т. Д.
Том Стикель,
2
Unity 3.5 уже поддерживает регистрацию на основе соглашений: nuget.org/packages/Unity/3.5.1404 . Устранить один недостаток ;-)
Владимир Дорохов
116

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

Вот краткое резюме из поста:

Вывод

Ninject, безусловно, самый медленный контейнер.

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

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

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

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

Некоторая информация о Common Service Selector Library с сайта:

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

Обновить

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

04.11.2011: «добавлен Simple Injector , производительность лучшая из всех конкурсантов».

Пранав Шах
источник
(Из ссылки для сравнения) Обновлен недавно, интересно посмотреть различия в скорости (плюс матрица основных функций). Спасибо.
Iko
Это сравнение не так надежно, потому что, насколько мне известно, Ninject имеет расширения как для перехвата, так и для конфигурации XML, тогда как в сравнении утверждается, что это не так.
Даниил
15
это очень количественное сравнение. как насчет неэффективных функций, таких как размер файла или количество необходимых зависимостей? Кроме того, субъективные меры, такие как качество документации или удобство использования были бы полезны. Я хочу сказать, что есть и другие факторы, помимо скорости.
FistOfFury
1
Как и Джереми Миллер, в прошлом автор StructureMap говорил ... перефразируя: «Конечно, есть более быстрые контейнеры IOC, но им не хватает полного набора функций».
Том Стиккель
проверить это: iocservicestack.net
Раджеш Джинага
49

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

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

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

Броди
источник
5
Существует обновление к посту .Net DI Container Speed ​​Redux : В итоге был принят неверный подход для Unity. С новыми измерениями Unity выглядит намного лучше.
Фолькер фон Эйнем
33

Отказ от ответственности: По состоянию на начало 2015, существует большое сравнение IoC контейнер особенности от Джимми Богард , вот резюме:

Контейнеры по сравнению:

  • Autofac
  • Ninject
  • Простой инжектор
  • StructureMap
  • Единство
  • Виндзор

Сценарий таков: у меня есть интерфейс 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)

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

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

Единство

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

Виндзор

var container = new WindsorContainer();
container.Register(Classes.FromAssemblyContaining<IMediator>().Pick().WithServiceAllInterfaces());
container.Register(Classes.FromAssemblyContaining<Ping>().Pick().WithServiceAllInterfaces());
container.Kernel.AddHandlersFilter(new ContravariantFilter());
  • Открытые дженерики: да, неявно
  • Несколько открытых дженериков: да, неявно
  • Общая противоположность: да, с пользовательским расширением
STRATOVARIUS
источник
Превосходно! Кстати, приведенное выше резюме пропустило Виндзор, но оно доступно в оригинальной статье Джимми.
Луи
Ничего себе раньше никто не предупреждал ((добавил Виндзор, спасибо @Louis
stratovarius,
21

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

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

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

jgauffin
источник
Привет @abatishchev! :) ... оригинальная идея заключалась в том, чтобы убедиться, что сторонние и встроенные методы были на одном уровне; многие «регистровые» методы должны поставляться отдельно (например, RegisterControllers()для MVC), поэтому я подумал, что стоит разрабатывать вокруг этого случая. (Это было разработано 5+ лет назад.)
Николас Блумхардт
1
@NicholasBlumhardt: Привет! :) Извините за поздний ответ, уведомление потеряно среди других. На самом деле такой смысл для последовательности имеет смысл для меня. Как ты думаешь сейчас, как бы ты это спроектировал?
Абатищев
@abatishchev Я не согласен с jgauffin. Методы расширения не закрыты для расширения, они являются расширением. Вы пишете ядро ​​своего фреймворка, который может делать все, что нужно, и с помощью методов расширения вы предоставляете некоторую дополнительную функциональность, может быть, некоторые помощники по умолчанию, но любой другой может свободно писать свои собственные расширения. Я бы сказал, если ваш фреймворк принимает методы расширения для его расширения, то это хороший фреймворк.
t3chb0t
6

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

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

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

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

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

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

Надеюсь, кто-то еще может дать сравнение, основанное на непосредственном опыте.

ocodo
источник
2
Единство довольно хорошо. Он охватывает большую часть того, что нужно, хотя некоторые люди жалуются на то, что он не разрешает циклические зависимости. Я люблю это. Я делаю все, что мне нужно.
Дмитрий Нестерук
Многие разработчики используют Castle.Windsor, даже не подозревая об этом. Это Ioc по умолчанию для NHibernate . (По крайней мере с FluentNHibernate, который я вчера загрузил). Я также видел реализацию NHibernate, которая использует LinFu nstead
k3b
5

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

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

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

k3b
источник