免责声明:截至2015年初,Jimmy Bogard对IoC容器的功能进行了很好的比较,以下是摘要:
比较的容器:
- Autofac
- Ninject
- Simple Injector
- StructureMap
- Unity
- Windsor
场景是这样的:我有一个接口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> { }
public class PingAsyncHandler : IAsyncRequestHandler<PingAsync, Pong> { }
public class PingedHandler : INotificationHandler<Pinged> { }
public class PingedAlsoHandler : INotificationHandler<Pinged> { }
public class GenericHandler : INotificationHandler<INotification> { }
public class PingedAsyncHandler : IAsyncNotificationHandler<PingedAsync> { }
public class PingedAlsoAsyncHandler : IAsyncNotificationHandler<PingedAsync> { }
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);
- 开放式泛型:是的,隐式
- 多个开放式泛型:是的,隐式
- 泛型逆变性:是的,使用用户构建的扩展
Simple Injector
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<>));
});
});
- 开放式泛型: 是的, 显式声明
- 多重开放式泛型: 是的, 显式声明
- 泛型逆变性: 是的, 隐式声明
Unity
container.RegisterTypes(AllClasses.FromAssemblies(typeof(Ping).Assembly),
WithMappings.FromAllInterfaces,
GetName,
GetLifetimeManager);
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(翻译不确定具体含义)
温莎(Windsor)
var container = new WindsorContainer();
container.Register(Classes.FromAssemblyContaining<IMediator>().Pick().WithServiceAllInterfaces());
container.Register(Classes.FromAssemblyContaining<Ping>().Pick().WithServiceAllInterfaces());
container.Kernel.AddHandlersFilter(new ContravariantFilter());
- 开放式泛型:是的,隐式地
- 多重开放式泛型:是的,隐式地
- 泛型逆变性:是的,需要用户构建扩展