主要的C#DI/IoC框架如何比较?

oco*_*odo 298 c# dependency-injection ninject ioc-container unity-container

冒着进入神圣战争领域的风险,这些流行的DI/IoC框架有哪些优点和缺点,可以轻松地被认为是最好的?..:

  • Ninject
  • 统一
  • Castle.Windsor
  • Autofac
  • StructureMap

我还没有列出其他用于C#的DI/IoC框架吗?

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

更新:

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

我意识到关于这个主题的大多数意见可能都有偏见,但我希望有人花时间研究所有这些框架,并且至少进行了一般性的客观比较.

如果以前没有这样做,我非常愿意自己进行调查,但我认为至少有一些人已经这样做了.

第二次更新:

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

Mar*_*ann 223

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

解释几个DIC之间差异的表格

  • 我已经阅读了你的书的MEAP,并一直在想你为什么离开Ninject呢? (39认同)
  • @Mark,谢谢你,希望你的答案可能包括Ninject(重要的是,不仅因为围绕它的新炒作,还因为它使用了新的语言功能.) (25认同)
  • 与AutoFac类似的Ninject有很多种方式,它由NUGET团队使用,而最受欢迎的下载IOC容器也是如此.我很失望,这不是在Mark的依赖注入.NET书中.如果有一个行业看起来的第二版,希望它会进入书中.我要么遇到Unity,MEF(不是真正的DI),Ninject或者StructurMap,我还没有登陆使用spring.net或autofac等的合同或远程演出...... (3认同)
  • 部分答案可以在这里找到:http://www.manning-sandbox.com/thread.jspa?threadID = 38943 (2认同)
  • Unity 3.5已经支持基于约定的注册:https://www.nuget.org/packages/Unity/3.5.1404.消除一个缺点;-) (2认同)

Pra*_*hah 113

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

以下是帖子的快速摘要:

结论

Ninject绝对是最慢的容器.

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

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

特别简单的注射器似乎是一个不错的选择.它非常快,具有良好的文档,并且还支持拦截和通用装饰器等高级场景.

您也可以尝试使用公共服务选择器库,并希望尝试多个选项,看看什么最适合您.

从网站上获得有关公共服务选择器库的一些信息:

该库提供了IoC容器和服务定位器的抽象.使用该库允许应用程序间接访问功能,而不依赖于硬引用.希望使用此库,第三方应用程序和框架可以开始利用IoC /服务位置,而无需将自己与特定实现联系起来.

更新

13.09.2011: FunqMunq被添加到参赛者名单中.图表也进行了更新,Spring.NET由于性能不佳而被删除.

04.11.2011: "添加了Simple Injector,性能是所有参赛者中最好的".

  • 这是一个非常量化的比较.那些非性能功能如文件大小或所需的依赖项数量呢?此外,文档质量或可用性等主观测量也会有所帮助.我的观点是除速度外还有其他因素需要考虑. (15认同)

bro*_*die 49

请阅读Philip Mat撰写的这篇伟大的.Net DI容器比较博客.

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

他建议使用Autofac,因为它小巧,快速且易于使用......我同意.UnityNinject似乎是他测试中最慢的.

  • 帖子[.Net DI Container Speed Redux]有更新(http://philipm.at/2011/0819/):在最后一行,首先采用了错误的Unity方法.通过新的测量,Unity看起来更好. (5认同)

str*_*ius 31

免责声明:自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; 
}
Run Code Online (Sandbox Code Playgroud)

然后我创建了一组基本的请求/响应/通知:

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 { }
Run Code Online (Sandbox Code Playgroud)

我有兴趣看一些关于泛型容器支持的事情:

  • 开放式泛型的设置(轻松注册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 */ }
Run Code Online (Sandbox Code Playgroud)

Autofac

var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof (IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof (Ping).Assembly).AsImplementedInterfaces();
Run Code Online (Sandbox Code Playgroud)
  • 开放式泛型:是的,含蓄的
  • 多个开放式泛型:是的,含蓄地
  • 通用逆转:是的,明确的

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);
Run Code Online (Sandbox Code Playgroud)
  • 开放式泛型:是的,含蓄的
  • 多个开放式泛型:是的,含蓄地
  • 通用逆转:是的,使用用户构建的扩展

简单的注射器

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);
Run Code Online (Sandbox Code Playgroud)
  • 打开泛型:是的,明确的
  • 多个开放式泛型:是的,明确的
  • 通用逆转:是,隐含地(使用更新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<>));
    });
});
Run Code Online (Sandbox Code Playgroud)
  • 打开泛型:是的,明确的
  • 多个开放式泛型:是的,明确的
  • 通用逆转:是的,含蓄的

统一

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;
}
Run Code Online (Sandbox Code Playgroud)
  • 开放式泛型:是的,含蓄的
  • 多个开放式泛型:是的,具有用户构建的扩展
  • 通用逆变:derp

温莎

var container = new WindsorContainer();
container.Register(Classes.FromAssemblyContaining<IMediator>().Pick().WithServiceAllInterfaces());
container.Register(Classes.FromAssemblyContaining<Ping>().Pick().WithServiceAllInterfaces());
container.Kernel.AddHandlersFilter(new ContravariantFilter());
Run Code Online (Sandbox Code Playgroud)
  • 开放式泛型:是的,含蓄的
  • 多个开放式泛型:是的,含蓄地
  • 通用逆转:是的,使用用户构建的扩展


jga*_*fin 21

实际上有大量的IoC框架.似乎每个程序员都试图在他们职业生涯的某个阶段写一个.也许不发表它,但要学习内部运作.

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

其他一些框架:


oco*_*odo 6

那么,看看我迄今发现的最佳比较是:

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

我感兴趣的一点是那些使用DI/IoC框架并喜欢/不喜欢它的人,StructureMap似乎名列前茅.

同样来自民意调查,似乎Castle.WindsorStructureMap似乎最受青睐.

有趣的是,UnitySpring.Net似乎是最受欢迎的流行选项.(我正在考虑Unity的懒惰(以及微软的徽章/支持),但我现在会更密切地关注Castle Windsor和StructureMap.)

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

希望其他人可以根据直接经验提供比较.

  • 团结非常好.它涵盖了人们需要的大部分内容,尽管有些人抱怨它没有解决循环依赖.我喜欢它.我做我需要的一切. (2认同)

k3b*_*k3b 5

在我写这篇文章时,请参阅google代码上net-ioc-frameworks的比较,包括linfu和spring.net.

我在spring.net工作:它有很多功能(aop,库,文档......),并且在dotnet和java-world中有很多经验.功能模块化,所以你不必采取所有功能.这些功能是数据库抽象,loggingabstraction等常见问题的抽象.但是,进行和调试IoC配置是很困难的.

从我到目前为止所读到的内容:如果我必须选择一个小型或中型项目,我将使用ninject,因为ioc-configuration已完成并可在c#中调试.但我还没有使用它.对于大型模块化系统,由于抽象库,我会留在spring.net.