主要的C#DI / IoC框架如何比较?[关闭]


308

冒着进入神圣战争领土的风险,这些流行的DI / IoC框架的优点和缺点是什么,可以轻易地认为是最好的吗?..:

  • Ninject
  • 统一
  • 温莎城堡
  • Autofac
  • 结构图

我这里没有列出其他的C#DI / IoC框架吗?

就我的用例而言,我正在构建客户端WPF应用程序和WCF / SQL服务基础结构,易用性(尤其是在语法简洁明了方面),一致的文档,良好的社区支持和性能都是重要因素。由我选择。

更新:

引用的资源和重复的问题似乎已经过时了,知道所有这些框架的人能挺身而出并提供一些真正的见解吗?

我意识到,关于该主题的大多数意见可能会带有偏见,但我希望有人花时间研究所有这些框架,并且至少要有一个客观的比较。

如果以前没有做过,我很愿意进行自己的调查,但是我认为这至少是一些人已经做过的。

第二次更新:

如果您确实有多个DI / IoC容器的使用经验,请对这些容器的优缺点进行排名和总结,谢谢。这不是发现人们制作的所有晦涩的小容器的一种练习,我正在寻找流行的(和活动的)框架之间的比较。


1
与[Ninject vs Unity for DI](stackoverflow.com/questions/1054801/ninject-vs-unity-for-di)相同的问题,但可能是时候进行跟进了。
Matthew Flaschen

2
[比较城堡温莎,统一和StructureMap](的可能重复stackoverflow.com/questions/2216684/...
毛雅伯

@slomojo:可能重复。stackoverflow.com/questions/4509458/ioc-comparisions-closed。也有链接显示答案中IoC的受欢迎程度。看看它。
dhinesh 2011年

@chibacity-我在4个项目上使用了它,前两个是非常基本的,没有问题,后两个,Unity在构造函数注入,可维护性和可读性方面给我们带来了很多问题。我们最终将Unity从这两者中剔除,然后将其替换为StructureMap,构造函数注入非常简单,配置干净且可维护。在我个人时间里,我玩过AutoFac,但我发现它很奇怪,需要一些文档来更好地理解它。其余的我只能评论我读过的东西。
菲尔

我们遇到的一个问题是SSRS,它无声地失败了,逐步浏览了我们无法弄清失败原因的代码,其中的异常模棱两可。我们花了一周的时间编写解决方法以使其正常运行。最终,当我们移至StructureMap时,我们又进行了一次尝试,并在几分钟之内使用“ ObjectFactory.WhatDoIHave()”了解到IoC是在将程序集加载到AppDomain之前构造的,因此这些接口从未在混凝土中注册。类型。
菲尔

Answers:


225

尽管对这个问题的全面回答占据了我书的数百页,但是下面是我仍在进行的快速比较表:

一张表,解释几个DIC之间的区别


40
我已经读过您的书的MEAP,并且想知道为什么您不将Ninject排除在书本之外?
Martin Owen

2
可以在这里找到部分答案:manning-sandbox.com/thread.jspa?threadID=38943
Mark Seemann

25
@Mark,谢谢您,希望您的回答可以包括Ninject(重要的是,不仅因为周围有新的炒作,而且还因为它使用了新的语言功能。)
ocodo 2011年

3
Ninject虽然与AutoFac相似,但在很多方面都非常有用,它由NUGET团队使用,并且最受欢迎的IOC容器已被广泛使用。我很失望,因为它不在Mark的.NET书中的Dependency Injection中。如果有一个第二版的行业外观,希望它能被纳入本书。我遇到Unity,MEF(不是真正的DI),Ninject或StructurMap的问题,我只是还没有进入使用spring.net或autofac等的合同或远程演出中……
Tom Stickel 2014年

2
Unity 3.5已经支持基于约定的注册:nuget.org/packages/Unity/3.5.1404。消除一个不利条件;-)
弗拉基米尔·多罗霍夫(Fladimir Dorokhov)

116

我遇到了另一个性能比较(2014年4月10日最新更新)。它比较以下内容:

这是帖子的快速摘要:

结论

Ninject绝对是最慢的容器。

MEF,LinFu和Spring.NET比Ninject更快,但仍然很慢。接下来是AutoFac,Catel和Windsor,其次是StructureMap,Unity和LightCore。Spring.NET的一个缺点是只能使用XML进行配置。

SimpleInjector,Hiro,Funq,Munq和Dynamo提供了最佳性能,它们非常快。试试看!

特别是简单喷射器似乎是一个不错的选择。它的速度非常快,拥有完善的文档,还支持拦截和通用装饰器等高级方案。

您还可以尝试使用通用服务选择器库,并希望尝试多个选项,然后查看最适合您的方法。

该站点上有关Common Service Selector Library的一些信息:

该库提供了IoC容器和服务定位器的抽象。使用该库可使应用程序间接访问功能,而无需依赖硬引用。希望是,使用该库,第三方应用程序和框架可以开始利用IoC /服务位置,而不必将自己束缚于特定的实现上。

更新资料

2011年9月13日FunqMunq被添加到参赛者列表中。图表也进行了更新,并且由于性能不佳而删除了Spring.NET。

2011年4月11日: “添加了简单喷射器,性能是所有参赛者中最好的”。


(来自下面的比较链接)最近更新,有趣的是看到了速度差异(加上基本特征矩阵)。谢谢。
lko

这种比较不是那么可靠,因为据我所知,Ninject具有Interception和XML配置的扩展,而比较却没有。
丹尼尔(Daniel)

15
这是一个非常定量的比较。诸如文件大小或所需依赖项数量之类的非性能功能又如何呢?此外,诸如文档质量或可用性之类的主观衡量指标也将有所帮助。我的观点是,除了速度之外,还有其他因素需要考虑。
FistOfFury 2014年

1
就像Je​​remy Miller一样,StructureMap的作者过去也曾说过……释义-确保有更快的IOC容器,但它们缺乏完整的功能。
汤姆·斯蒂克2014年


49

只需阅读Philip Mat撰写的精彩的.Net DI容器比较博客

他对一些性能进行了比较测试。

他建议使用Autofac,因为它体积小,速度快,易于使用...我同意。看来UnityNinject在他的测试中是最慢的。


5
.NET DI Container Speed Redux的更新:最重要的是,Unity首先采用了错误的方法。通过新的测量,Unity看起来要好得多。
Volker von Einem 2012年

33

免责声明: 2015年年初一样,有IOC容器的一个伟大的比较功能吉米博加德,这里是一个总结:

比较容器:

  • Autofac
  • Ninject
  • 简单喷油器
  • 结构图
  • 统一
  • 温莎

场景是这样的:我有一个接口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)

结构图

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());
  • 开放的泛型:是的,隐式
  • 多个开放泛型:是的,隐式
  • 通用的逆差:是的,具有用户构建的扩展名

优秀的!顺便说一句,上面的摘要错过了温莎,但可以在吉米的原始文章中找到。
路易

哇,以前没人警告过(:我加了windsor,谢谢@Louis
stratovarius

21

实际上,有很多IoC框架。似乎每个程序员都试图在其职业生涯的某个时候写一个。也许不发布它,而是学习其内部运作方式。

我个人更喜欢autofac,因为它非常灵活并且具有适合我的语法(尽管我真的很讨厌所有的注册方法都是扩展方法)。

其他一些框架:


嗨@abatishchev!:) ...最初的想法是确保第三方方法和内置方法在同一基础上;许多“注册”方法必须单独提供(例如,RegisterControllers()对于MVC),因此我认为围绕这​​种情况进行设计是值得的。(这是5年前设计的)
Nicholas Blumhardt 2014年

1
@NicholasBlumhardt:嗨!:)很抱歉,您的回复太晚,其他人也失去了通知。实际上,这种一致性对我来说很有意义。您现在的想法如何,如何设计?
abatishchev 2014年

@abatishchev我不同意jgauffin。扩展方法没有为扩展而关闭,它们是扩展。您编写了可以完成所有工作的框架核心,并使用扩展方法提供了一些其他功能,也许提供了一些默认的帮助程序,但其他任何人都可以自由编写自己的扩展。我要说的是,如果您的框架接受扩展方法来对其进行扩展,那么它就是一个很好的框架。
t3chb0t

6

好了,环顾四周,到目前为止,我发现的最佳比较是:

这是2010年3月进行的民意调查。

我感兴趣的一点是,使用过DI / IoC框架并且喜欢/不喜欢它的人,StructureMap似乎排在首位。

同样从民意测验来看,Castle.WindsorStructureMap似乎是最受青睐的。

有趣的是,UnitySpring.Net似乎是最普遍不喜欢的流行选项。(我出于懒惰(和Microsoft徽章/支持)考虑使用Unity,但现在我将更仔细地研究Castle Windsor和StructureMap。)

当然,这(?)不适用于2010年5月发布的Unity 2.0。

希望其他人可以根据直接经验进行比较。


2
团结很好。它涵盖了大多数需求,尽管有些人抱怨它不能解决循环依赖。我喜欢它。我做我需要的一切。
Dmitri Nesteruk 2011年

许多开发人员甚至都不知道在使用Castle.Windsor。它是NHibernate的默认Ioc 。(至少昨天我用FluentNHibernate掉线了)。我还看到了使用LinFu nstead的NHibernate实现
k3b

5

在我撰写本文时,未在您的列表中找到google代码(包括linfu和spring.net)net-ioc-frameworks的比较。

我在spring.net上工作:它具有许多功能(aop,库,docu等),并且在dotnet和Java世界中都有很多经验。这些功能是模块化的,因此您不必使用所有功能。这些功能是常见问题(例如数据库抽象,日志记录抽象)的抽象。但是,很难进行和调试IoC配置。

到目前为止,我的读物是:如果我必须选择中小型项目,那么我将使用ninject,因为ioc配置已完成并且可以在c#中调试。但是我还没有使用它。对于大型模块化系统,由于抽象库,我会留在spring.net上。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.