主要なC#DI / IoCフレームワークはどのように比較されますか?[閉まっている]


308

聖戦領域に足を踏み入れるリスクがある場合、これらの一般的なDI / IoCフレームワークの長所と短所は何ですか?..:

  • Ninject
  • ユニティ
  • Castle.Windsor
  • Autofac
  • StructureMap

ここに記載していない他のC#のDI / IoCフレームワークはありますか?

私のユースケースのコンテキストでは、クライアントWPFアプリとWCF / SQLサービスインフラストラクチャを構築しています。使いやすさ(特に明確で簡潔な構文に関して)、一貫したドキュメント、優れたコミュニティサポートとパフォーマンスはすべて重要な要素です私の選択で。

更新:

引用されているリソースと重複する質問は古くなっているようですが、これらすべてのフレームワークについての知識を持つ誰かが前に出て、実際の洞察を提供できますか?

私はこのテーマに関するほとんどの意見が偏っている可能性があることを理解していますが、誰かがすべてのこれらのフレームワークを研究するために時間をかけ、少なくとも一般的に客観的な比較を持つことを望んでいます。

これまでに行われていない場合は、自分で調査することをいといませんが、これは少なくとも数人がすでに行っていることだと思いました。

2回目の更新:

複数のDI / IoCコンテナの経験がある場合は、それらの長所と短所をランク付けして要約してください。ありがとうございます。これは、人々が作成したあいまいな小さなコンテナーをすべて発見するための演習ではありません。人気のある(そしてアクティブな)フレームワークの比較を探しています。


1
[Ninject vs Unity for DI](stackoverflow.com/questions/1054801/ninject-vs-unity-for-di)と同じ質問ですが、フォローアップの時間になるかもしれません。
Matthew Flaschen、2011年

2
[Castle Windsor、Unity、StructureMapの比較](stackoverflow.com/questions/2216684/…)の複製の可能性
Mauricio Scheffer

@slomojo:重複の可能性があります。stackoverflow.com/questions/4509458/ioc-comparisions-closed。また、回答にIoCの人気度を示すリンクがあります。それを見てください。
dhinesh、2011年

@chibacity-私はそれを使用しました... 4つのプロジェクト、最初の2つは本当に基本的な問題ではなく、次の2つは、Unityはコンストラクターの注入、保守性、可読性に関して非常に多くの問題を引き起こしました。結局、Unityを両方から取り除き、StructureMapに置き換えました。コンストラクターの注入は非常に単純で、構成はクリーンで保守可能でした。私の個人的な時間では、私はAutoFacで遊んだことがありますが、面倒なことに気づき、ドキュメントを理解して理解する必要があります。残りは私が読んだことについてのみコメントできます。
Phill

私たちが抱えていた1つの問題はSSRSに関するものでした。それはサイレントに失敗し、コードをステップ実行すると、なぜ失敗するのか理解できず、例外があいまいでした。1週間かけて回避策を記述し、機能させました。最終的に、StructureMapに移動したときにもう一度試みましたが、 'ObjectFactory.WhatDoIHave()'を使用して数分以内に、アセンブリがAppDomainに読み込まれる前にIoCが構築されているため、インターフェイスが具象に登録されないことがわかりました。タイプ。
Phill

回答:


225

この質問に対する包括的な回答は私の本の数百ページを占めますが、ここでは私がまだ取り組んでいる簡単な比較表を示します。

複数のDICの違いを説明する表


40
私はあなたの本のMEAPを読んだのですが、なぜNinjectを使わなくなったのか疑問に思っていますか?
Martin Owen

2
部分的な答えはここにあります:manning-sandbox.com/thread.jspa?threadID
Mark Seemann

25
@Mark、ありがとうございます。うまくいけば、あなたの答えにはNinjectが含まれる可能性があります(重要なのは、それを取り巻く新しい誇大宣伝のためだけでなく、新しい言語機能の使用のためでもあります。)
ocodo

3
NinjectはAutoFacに似ていますが、NUGETチームによって使用され、最も人気のあるダウンロードされたIOCコンテナーが使用されています。.NETブックのMarkのDependency Injectionに含まれていないことにがっかりしました。業界の見た目に第2版がある場合、うまくいけば、それが本になると思います。Unity、MEF(実際のDIではない)、Ninject、またはStructurMapのいずれかに遭遇しましたが、spring.netやautofacなどを使用する契約またはリモートギグにまだ着陸していません...
Tom Stickel

2
Unity 3.5は既に規約に基づく登録をサポートしています:nuget.org/packages/Unity/3.5.1404。1つの欠点を取り除く;-)
Vladimir Dorokhov '19年

116

別のパフォーマンス比較に遭遇しました(最新の更新2014年4月10日)。以下を比較します。

これが投稿の簡単な要約です:

結論

Ninjectは間違いなく最も遅いコンテナです。

MEF、LinFu、Spring.NETはNinjectより高速ですが、それでもかなり低速です。次にAutoFac、Catel、Windsorが続き、StructureMap、Unity、LightCoreが続きます。Spring.NETの欠点は、XMLでのみ構成できることです。

SimpleInjector、Hiro、Funq、Munq、およびDynamoは最高のパフォーマンスを提供し、非常に高速です。それらを試してみてください!

特にSimple Injectorは良い選択のようです。これは非常に高速で、優れたドキュメントがあり、傍受や一般的なデコレータなどの高度なシナリオもサポートしています。

また、Common Service Selector Libraryを使用してみて、うまくいけば複数のオプションを試してみて、何が最適かを確認することもできます。

サイトからのCommon Service Selector Libraryに関するいくつかの情報:

ライブラリは、IoCコンテナーとサービスロケーターの抽象化を提供します。ライブラリを使用すると、ハード参照に依存することなく、アプリケーションが機能に間接的にアクセスできます。このライブラリを使用すると、サードパーティのアプリケーションやフレームワークが特定の実装に縛られることなくIoC / Service Locationを活用できるようになることが期待されます。

更新

13.09.2011: FunqMunqが出場者のリストに追加されました。グラフも更新され、Spring.NETはパフォーマンスが低いため削除されました。

2011年4月11日:シンプルインジェクターを追加し、パフォーマンスはすべての競技者の中で最高です」。


(比較リンクをたどることから)最近更新されました。速度の違い(および基本的な機能マトリックス)を見て興味深いです。ありがとう。
lko

私の知る限り、NinjectにはインターセプションとXML構成の両方の拡張機能があるため、この比較はそれほど信頼できませんが、比較ではそうではありません。
ダニエル

15
これは非常に定量的な比較です。ファイルサイズや必要な依存関係の数などの非パフォーマンス機能についてはどうですか?さらに、ドキュメントの品質や使いやすさなどの主観的な指標が役立ちます。私のポイントは、速度以外にも考慮すべき要素があるということです。
FistOfFury 14年

1
Jeremy Millerのように、StructureMapの作成者は過去に言っています...言い換え-確かに高速のIOCコンテナがありますが、完全な機能セットがありません。
トムスティッケル、2014年

これをチェックしてください:iocservicestack.net
Rajesh Jinaga 2017年

49

Philip Matによるこの素晴らしい.Net DIコンテナー比較ブログを読んでください。

彼はいくつかの徹底的なパフォーマンス比較テストを行っています。

Autofacは小さく、高速で、使いやすいので、彼は推奨しています... と思わユニティNinjectは彼のテストで最も遅いです。


5
投稿.Net DI Container Speed Reduxに更新があります:一番下の行では、最初にUnityに対して間違ったアプローチが取られていました。新しい測定により、Unityはより良く見えます。
Volker von Einem 2012年

33

免責事項: 2015年の初めの時点で、Jimmy Bogardの 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 <、>を簡単に登録)
  • オープンジェネリックの複数登録のセットアップ(2つ以上の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;
}
  • ジェネリックを開く:はい、暗黙的に
  • 複数のオープンジェネリック:はい、ユーザーが作成した拡張機能
  • 一般的な反変性:derp

ウィンザー

var container = new WindsorContainer();
container.Register(Classes.FromAssemblyContaining<IMediator>().Pick().WithServiceAllInterfaces());
container.Register(Classes.FromAssemblyContaining<Ping>().Pick().WithServiceAllInterfaces());
container.Kernel.AddHandlersFilter(new ContravariantFilter());
  • ジェネリックを開く:はい、暗黙的に
  • 複数のオープンジェネリック:はい、暗黙的に
  • 一般的な逆分散:はい、ユーザーが作成した拡張機能を使用

優れた!ところで、上記の要約はウィンザーを逃しましたが、それはジミーの元の記事で利用可能です。
Louis

うわー、誰もそれについて以前に警告していませんでした(:私はウィンザーを追加しました、@ Louisに感謝します
ストラトバリウス

21

実際、IoCフレームワークはたくさんあります。すべてのプログラマーがキャリアのある時点で1つを作成しようとするようです。多分それを公開するためではなく、内部の仕組みを学ぶためです。

autofacは非常に柔軟性があり、自分に合った構文を持っているので個人的に好みます(ただし、すべての登録メソッドが拡張メソッドであることは本当に嫌いです)。

他のいくつかのフレームワーク:


こんにちは@abatishchev!:) ...元のアイデアは、サードパーティのメソッドと組み込みのメソッドが同じ基盤にあることを確認することでした。多くの「登録」メソッドは個別に出荷する必要があるため(たとえばRegisterControllers()、MVCの場合)、その場合の設計は価値があると思いました。(これは5年以上前に設計されました。)
Nicholas Blumhardt 2014

1
@NicholasBlumhardt:こんにちは!:)返信が遅くなって申し訳ありません。通知が他のユーザーから失われました。実際、そのような一貫性のために私は理にかなっています。今はどう思いますか、どのように設計しますか?
abatishchev 2014

@abatishchev私はjgauffinに同意しません。拡張メソッドは拡張のために閉じられていません、それらは拡張です。フレームワークのコアを作成し、必要なすべてを実行できます。拡張メソッドを使用すると、いくつかの追加機能、おそらくデフォルトのヘルパーを提供できますが、他のユーザーは独自の拡張機能を自由に作成できます。あなたのフレームワークがそれを拡張する拡張メソッドを受け入れるなら、それは良いフレームワークだと私は言うでしょう。
t3chb0t

6

まあ、私がこれまでに見つけた最良の比較を見回した後、次のとおりです。

2010年3月に行われた投票です。

私にとって興味深い点の1つは、DI / IoCフレームワークを使用していて、フレームワークが好き/嫌いだった人々が、StructureMapを最上位に表示しているように見えることです。

また、投票結果から、Castle.WindsorStructureMapが最も支持されているようです。

興味深いことに、UnitySpring.Netは最も一般的に嫌われる人気のあるオプションのようです。(私は怠惰(およびMicrosoftバッジ/サポート)からUnityを検討していましたが、今はキャッスルウィンザーとストラクチャーマップをさらに詳しく見ていきます。)

もちろん、これはおそらく(?)2010年5月にリリースされたUnity 2.0には当てはまりません。

うまくいけば、他の誰かが直接の経験に基づいて比較を行うことができます。


2
団結はかなり良いです。必要なもののほとんどをカバーしていますが、循環依存関係を解決しないと不満を言う人もいます。大好きです。私は必要なすべてを行います。
Dmitri Nesteruk、2011年

多くの開発者が知らないうちにCastle.Windsorを使用しています。NHibernateのデフォルトのIocです。(少なくとも私は昨日FluentNHibernateでダウンロードしました)。また、LinFu nsteadを使用するNHibernate実装を見ました
k3b

5

このテキストを書いている間、リストにないlinfuとspring.netを含むGoogleコードnet-ioc-frameworksの比較については、を参照してください。

私はspring.netを使用しました:これには多くの機能(aop、libraries、docuなど)があり、dotnetとjava-worldでの経験はたくさんあります。機能はモジュール化されているため、すべての機能を使用する必要はありません。機能は、データベース抽象化、ロギング抽象化などの一般的な問題を抽象化したものです。ただし、IoC構成を実行してデバッグすることは困難です。

これまでに読んだことから:小規模または中規模のプロジェクトを選択する必要があった場合、ioc構成が行われ、c#でデバッグできるため、ninjectを使用します。しかし、私はまだそれを扱っていません。大規模なモジュール式システムの場合、抽象化ライブラリーがあるため、spring.netのままにします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.