Як порівняти основні рамки C # DI / IoC? [зачинено]


308

Загрожуючи потрапити на територію святої війни, які сильні та слабкі сторони цих популярних рамок DI / IoC, і чи можна їх легко вважати найкращими? ..:

  • Нінжект
  • Єдність
  • Замок.Віндзор
  • Автофактор
  • Структурна карта

Чи є інші рамки DI / IoC для C #, які я тут не перелічив?

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

Оновлення:

Цитовані ресурси та дублюючі запитання застаріли, чи може хтось із знаннями всіх цих рамок висунутись і дати реальне уявлення?

Я усвідомлюю, що більшість думок з цього приводу, ймовірно, є необ’єктивним, але я сподіваюся, що хтось знайшов час для вивчення всіх цих рамок і мав принаймні об'єктивне порівняння.

Я дуже готовий провести власні розслідування, якщо цього раніше не робилося, але я припускав, що це було щось, принаймні, мало хто вже робив.

Друге оновлення:

Якщо у вас є досвід роботи з більш ніж одним контейнером DI / IoC, будь ласка, класифікуйте та узагальнюйте плюси та мінуси цих, дякую. Це не вправа розкривати всі незрозумілі маленькі контейнери, які люди виготовили, я шукаю порівняння між популярними (і активними) рамками.


1
Те саме питання, що і [Ninject vs Unity for DI] ( stackoverflow.com/questions/1054801/ninject-vs-unity-for-di ), але може бути час для подальших дій.
Метью Флашен

2
можливий дублікат [Порівняння Castle Windsor, Unity and StructureMap] ( stackoverflow.com/questions/2216684/… )
Маурісіо Шеффер

@slomojo: Можливий дублікат. stackoverflow.com/questions/4509458/ioc-comparisions-closed . Також є посилання, яке показує популярність IoC у відповіді. Погляньте на це.
dhinesh

@chibacity - я використав це на 4 проектах, перші два насправді були основними, жодних проблем, другі два, Unity викликав у нас стільки проблем, коли справа стосувалася введення конструкторів, ремонтопридатності, читабельності. Ми закінчили видобуток Unity з обох і замінили його на StructureMap, введення конструктора було мертвим простим, конфігурація була чистою та ремонтопридатною. В свій особистий час я грав з AutoFac, але я вважаю це чудово, мені потрібна документація, щоб краще зрозуміти це. Решту я можу коментувати лише те, що я прочитав.
Філ

Одне з проблем у нас було з SSRS, воно мовчало виходило з ладу і перебираючи код, ми не могли зрозуміти, чому він не працює, виняток був неоднозначним. Ми витратили тиждень, пишучи роботи, щоб його працювати. Зрештою, коли ми перейшли до StructureMap, у нас була ще одна спроба, і за лічені хвилини, використовуючи 'ObjectFactory.WhatDoIHave ()', ми дізналися, що IoC будується до того, як збірки завантажуються в AppDomain, тому інтерфейси ніколи не були зареєстровані в конкретні типи.
Філ

Відповіді:


225

Хоча вичерпна відповідь на це питання займає сотні сторінок моєї книги , ось таблиця швидкого порівняння, над якою я ще працюю:

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


40
Я читав МЕПУ вашої книги і цікавився, чому ви залишили з нього Нінжекта?
Мартін Оуен

2
Часткову відповідь можна знайти тут: manning-sandbox.com/thread.jspa?threadID=38943
Марк

25
@ Марк, спасибі за це, сподіваємось, ваша відповідь може включати 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 пропонують найкращі показники, вони надзвичайно швидкі. Спробуйте їх!

Особливо простий інжектор здається хорошим вибором. Це дуже швидко, має гарну документацію, а також підтримує передові сценарії, такі як перехоплення та загальні декоратори.

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

Деякі відомості про бібліотеку вибору спільних служб із сайту:

Бібліотека забезпечує абстрагування контейнерів IoC та локаторів обслуговування. Використання бібліотеки дозволяє додатку опосередковано отримувати доступ до можливостей, не покладаючись на жорсткі посилання. Сподіваємось, що за допомогою цієї бібліотеки сторонні програми та фреймворки можуть почати використовувати IoC / Service Location, не прив'язуючи себе до конкретної реалізації.

Оновлення

13.09.2011: Funq і Munq були внесені до списку учасників. Діаграми також були оновлені, і Spring.NET було видалено через низьку продуктивність.

04.11.2011: "додано Simple Injector . Виступ найкращий з усіх учасників".


(З наступного посилання на порівняння) Оновлено нещодавно, цікаво побачити різниці швидкостей (плюс матриця основних функцій). Дякую.
lko

Це порівняння не настільки надійне, оскільки, наскільки я знаю, Ninject має розширення як для перехоплення, так і для конфігурації XML, тоді як порівняння констатує, що це не так.
Даніель

15
це дуже кількісне порівняння. як щодо таких функцій, як розмір файлу чи кількість необхідних залежностей? Крім того, корисними будуть такі суб'єктивні заходи, як якість документації чи зручність використання. Моя думка, є й інші фактори, які не враховують швидкість.
FistOfFury

1
Як і Джеремі Міллер, автор StructureMap раніше говорив ... перефразовуючи - Це впевнені, що є швидші контейнери МОК, але їм не вистачає повного набору функцій.
Том Стікель

перевірити це: iocservicestack.net
Раджеш Джинага

49

Просто прочитайте цей чудовий блог порівняння контейнерів .Net DI від Філіпа Мата.

Він робить ретельні тести порівняння продуктивності;

Він рекомендує Autofac, оскільки він невеликий, швидкий та простий у користуванні ... Я згоден. Здається, що Єдність і Нінжект - найповільніші в його випробуваннях.


5
Повідомлення є оновленням. NET DI Container Speed ​​Redux : У нижньому рядку був неправильний підхід, застосований в першу чергу для Unity. З новими вимірами Unity виглядає набагато краще.
Волкер фон Ейнем

33

Відмова від відповідальності: Станом на початок 2015 року, існує велика порівняння IoC контейнер оснащений від Джиммі Богард , ось резюме:

Порівняні контейнери:

  • Автофактор
  • Нінжект
  • Простий інжектор
  • Структурна карта
  • Єдність
  • Віндзор

Сценарій такий: у мене є інтерфейс 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 */ }

Автофактор

var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof (IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof (Ping).Assembly).AsImplementedInterfaces();
  • Відкриті дженерики: так, неявно
  • Кілька відкритих дженериків: так, неявно
  • Загальне протиріччя: так, явно

Нінжект

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)

Структурна карта

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());
  • Відкриті дженерики: так, неявно
  • Кілька відкритих дженериків: так, неявно
  • Загальне протиріччя: так, з розширенням, побудованим користувачем

Відмінно! До речі, вищезгаданий підсумок пропустив Віндзор, але він доступний в оригінальній статті Джиммі.
Луї

Нічого собі ніхто не попереджав про це раніше (: Я додав Віндзор, спасибі @Louis
Stratovarius

21

Насправді є багато каркасів IoC. Схоже, кожен програміст намагається написати його в якийсь момент своєї кар’єри. Можливо, не публікувати його, а навчитися внутрішній роботі.

Я особисто віддаю перевагу автофаку, оскільки він досить гнучкий і має синтаксис, який мені підходить (хоча я дуже ненавиджу, що всі методи реєстрації є методами розширення).

Деякі інші рамки:


Привіт @abatishchev! :) ... первісна ідея полягала в тому, щоб сторонні та вбудовані методи були однакові; багато методів "реєстрації" мають поставлятись окремо (наприклад, RegisterControllers()для MVC), тому я вважав, що розробляти навколо цього випадку варто. (Це було розроблено 5+ років тому.)
Ніколас Блюмхардт

1
@NicholasBlumhardt: Привіт! :) Вибачте за несвоєчасну відповідь, повідомлення було загублено серед інших. Насправді така послідовність має для мене сенс. Як ви думаєте зараз, як би ви його спроектували?
абатищев

@abatishchev Я не згоден з jgauffin. Методи розширення не закриті для розширення, вони є розширенням. Ви пишете ядро ​​свого фреймворку, яке може зробити все, що слід, і за допомогою методів розширення ви надаєте додаткову функціональність, можливо, деякі помічники за замовчуванням, але будь-хто інший вільний написати власні розширення. Я б сказав, якщо ваша рамка приймає методи розширення, щоб розширити її, то це добре.
t3chb0t

6

Ну, оглянувши найкраще порівняння, яке я знайшов поки що:

Це опитування, проведене в березні 2010 року.

Мене цікавить одне те, що люди, які використовували рамки DI / IoC і любили / не любили це, начебто, StructureMap виходять на перше місце.

Також з опитування здається, що це Castle.Windsor та StructureMap здаються найбільш прихильними.

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

Звичайно, це, ймовірно, (?) Не стосується Unity 2.0, який був випущений у травні 2010 року.

Сподіваємось, хтось інший може надати порівняння на основі прямого досвіду.


2
Єдність досить гарна. Він охоплює більшу частину того, що потрібно, хоча деякі люди скаржаться на це, не вирішуючи кругової залежності. Я це люблю. Я роблю все, що мені потрібно.
Дмитро Нестерук

Багато розробників використовують Castle.Windsor, навіть не підозрюючи про це. Іок за замовчуванням для NHibernate . (Принаймні, з FluentNHibernate i вниз вчора). Я також бачив реалізацію NHibernate, яка використовує LinFu nstead
k3b

5

Дивіться для порівняння net-ioc-фреймворків у коді google включаючи linfu та spring.net, які відсутні у вашому списку, поки я пишу цей текст.

Я працював з spring.net: Він має багато можливостей (aop, бібліотеки, docu, ...), і є багато досвіду роботи з цим у dotnet та java-світі. Функції модульовані, тому вам не доведеться приймати всі функції. Особливості - це абстракції поширених питань, таких як абстракція баз даних, реєстрація абстракції. однак це важко зробити та налагодити IoC-конфігурацію.

З того, що я читав до цих пір: Якби мені довелося вибрати для малого або середнього проекту, я би використовував ninject, оскільки ioc-конфігурація робиться і виводиться з ладу в #. Але я ще не працював з цим. для великих модульних систем я б залишався з spring.net через бібліотеки абстракцій.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.