关于依赖注入:主要的C#DI / IoC框架如何比较?

How do the major C# DI/IoC frameworks compare?

冒着踏入圣战领域的风险,这些流行的DI/IOC框架有哪些优点和缺点,是否可以轻易地认为是最好的?…

  • 九针
  • 团结
  • 温莎城堡
  • AutoFac
  • 结构图

是否还有其他我没有列出的针对C的DI/IOC框架?

在我的用例中,我正在构建一个客户端WPF应用程序和一个WCF/SQL服务基础结构、易用性(特别是在清晰简洁的语法方面)、一致的文档、良好的社区支持和性能都是我选择的重要因素。

更新:

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

我意识到大多数人对这个问题的看法可能是有偏见的,但我希望有人花时间研究所有这些框架,并至少进行一个总体上客观的比较。

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

第二次更新:

如果您对多个DI/IOC容器有经验,请对这些容器的优缺点进行排名和总结,谢谢。这不是一个发现人们所做的所有模糊的小容器的练习,我正在寻找流行(和活跃)框架之间的比较。


虽然对这个问题的全面回答占据了我书中的数百页,但这里有一个我仍在研究的快速比较图表:

A table explaining difference between several DICs


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

  • AutoFac
  • Lightcore(网站是德语)
  • 林府
  • 九针
  • 娇小的
  • 简单注射器(所有参赛者中速度最快的)
  • 弹簧网
  • 结构图
  • 团结
  • 温莎
  • 希罗

以下是帖子中的简要总结:

Conclusion

Ninject is definitely the slowest container.

MEF, LinFu and Spring.NET are faster than Ninject, but still pretty
slow. AutoFac, Catel and Windsor come next, followed by StructureMap,
Unity and LightCore. A disadvantage of Spring.NET is, that can only be
configured with XML.

SimpleInjector, Hiro, Funq, Munq and Dynamo offer the best
performance, they are extremely fast. Give them a try!

Especially Simple Injector seems to be a good choice. It's very fast, has a good
documentation and also supports advanced scenarios like interception
and generic decorators.

您还可以尝试使用公共服务选择器库,并希望尝试多个选项,看看哪些选项最适合您。

站点中有关公共服务选择器库的一些信息:

The library provides an abstraction over IoC containers and service
locators. Using the library allows an application to indirectly access
the capabilities without relying on hard references. The hope is that
using this library, third-party applications and frameworks can begin
to leverage IoC/Service Location without tying themselves down to a
specific implementation.

更新

2011年9月13日:funq和munq加入了参赛名单。图表也更新了,Spring.net由于性能不佳而被删除。

2011年11月4日:"添加了简单的注入器,性能是所有参赛者中最好的"。


刚刚阅读这个伟大的.NET DI容器比较博客,作者是PhilipMat。

他做了一些彻底的性能比较测试;

  • AutoFac
  • 结构图
  • 九针
  • 团结
  • 温莎城堡
  • 弹簧网

他推荐自动空调,因为它体积小,速度快,使用方便…我同意。在他的测试中,Unity和Ninject似乎是最慢的。


disclaimer:早在2015年前,有一个比较大的IoC容器的特点从吉米宝佳,这里是一个总结:

集装箱:相对

  • autofac
  • ninject
  • 简单的注入器
  • structuremap
  • 统一
  • 温莎

这是的情况:有一个接口,imediator,其中可以发送一个单一的请求/响应一个或多个接收通知。

1
2
3
4
5
6
7
8
9
10
11
12
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;
}

在当时创造了一个基本的要求/反应/通知:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 { }

我感兴趣的东西看几regards与两个容器支持泛型。

  • 设置为开仿制药(注册irequesthandler <易>)
  • 设置多registrations大学开仿制药(两个或更多的 inotificationhandlers)

设置为通用的方差(注册新的基础inotification /创建请求管道) 我的新straightforward是漂亮的,他们只是两个控制台的输出:

1
2
3
4
5
6
7
8
9
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

1
2
3
4
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof (IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof (Ping).Assembly).AsImplementedInterfaces();
  • 开仿制药:是的,implicitly
  • 多开:是的,implicitly泛型
  • 通用逆变:是的,没有

ninject

1
2
3
4
5
6
7
8
9
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);
  • 开仿制药:是的,implicitly
  • 多开:是的,implicitly泛型
  • 通用逆变:是的,与用户内置的扩展

简单的注入器

1
2
3
4
5
6
7
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);
  • 开仿制药:是的,没有
  • 多开仿制药:是的,没有
  • 通用逆变:是的,implicitly(3.0和更新)

structuremap

1
2
3
4
5
6
7
8
9
10
11
12
13
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<>));
    });
});
  • 开仿制药:是的,没有
  • 多开仿制药:是的,没有
  • 通用逆变:是的,implicitly

统一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
}
  • 开仿制药:是的,implicitly
  • 多开仿制药:是的,与用户内置扩展
  • 通用逆变DERP:

温莎

1
2
3
4
var container = new WindsorContainer();
container.Register(Classes.FromAssemblyContaining<IMediator>().Pick().WithServiceAllInterfaces());
container.Register(Classes.FromAssemblyContaining<Ping>().Pick().WithServiceAllInterfaces());
container.Kernel.AddHandlersFilter(new ContravariantFilter());
  • 开仿制药:是的,implicitly
  • 多开:是的,implicitly泛型
  • 通用逆变:是的,与用户内置扩展


实际上,有很多国际奥委会框架。似乎每个程序员都在他们的职业生涯中的某个阶段尝试写一个。也许不是发布它,而是学习内部工作原理。

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

其他一些框架:

  • http://simpleinjector.codeplex.com/
  • 网址:http://microioc.codeplex.com/
  • 网址:http://munq.codeplex.com/
  • 网址:http://funq.codeplex.com/


好吧,在研究了迄今为止我发现的最好的比较之后:

  • http://www.sturmnet.org/blog/2010/03/04/poll-ioc-containers-for-net

  • http://www.sturmnet.org/blog/2010/03/04/poll-results-ioc-containers-for-net

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

我感兴趣的一点是,那些使用过DI/IOC框架并且喜欢/不喜欢它的人,structuremap似乎排在最前面。

而且从民意调查来看,城堡、温莎和建筑地图似乎是最受欢迎的。

有趣的是,Unity和Spring.net似乎是最不受欢迎的选择。(我考虑团结是因为懒惰(还有微软的徽章/支持),但现在我会更仔细地看温莎城堡和结构地图。)

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

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


在我编写本文时,请参阅,以了解有关Google代码上的NET IOC框架的比较,其中包括Linfu和Spring.net,它们不在您的列表中。

我使用Srp.NET:它有很多特性(AOP,库,DOCU,……),在dotnet和Java世界中有很多的经验。这些特性是模块化的,因此您不必使用所有特性。这些特性是对数据库抽象、日志抽象等常见问题的抽象。但是,很难完成和调试IOC配置。

从我目前为止读到的内容来看:如果我不得不选择一个中小型项目,我会使用ninject,因为IOC配置已经完成,并且可以在C_中调试。但我还没用过。对于大型模块化系统,由于抽象库的存在,我将继续使用Spring.net。