这个问题源于这样一个事实:我试图为MediatR:https://github.com/jbogard/MediatR/pull/14创建一个简单的Injector实现。
在试图解决通用处理程序接口的实现时,我遇到了麻烦。考虑以下通知处理程序接口:
public interface INotificationHandler<in TNotification>
where TNotification : INotification
{
void Handle(TNotification notification);
}INotifcation只是一个空的标记接口。
我为Pinged (实现INotification)事件定义了以下处理程序:
public class PingedHandler : INotificationHandler<Pinged>
{
public void Handle(Pinged notification) { }
}
public class PingedHandler2 : INotificationHandler<Pinged>
{
public void Handle(Pinged notification) { }
}还有一个通用处理程序(请注意,这应该处理每个INotification):
public class GenericHandler : INotificationHandler<INotification>
{
public void Handle(INotification notification) { }
}登记如下:
var container = new Container();
container.RegisterManyForOpenGeneric(
typeof (INotificationHandler<>),
(service, impls) => container.RegisterAll(service, impls),
AppDomain.CurrentDomain.GetAssemblies());现在我希望:
GetAllInstances<INotificationHandler<Pinged>>();来解决它所做的PingedHandler和PingedHandler2。但是它没有解析GenericHandler,因为它实现了INotificationHandler<INotification>而不是INotificationHandler<Pinged>。我想知道是否有一种方法可以让简单的喷射器搜索整个对象图并解析任何属于Pinged的东西。
我从史蒂文那里找到了关于协方差和对方差的博客文章,但我无法让它适用于我的例子。
发布于 2015-01-13 09:49:57
tl;dr:这是简单注射器v2.6.0中的一个缺陷/缺点,它在v2.7.0中得到了修正。问题中的配置(如下所示)现在确实起作用了。
总之,@qujck的回答和@Steven的评论:我能够通过安装带有以下配置的简单Injector v2.7.0-beta2 (实际上与问题中的配置相同)来使其工作:
// Simple Injector v3.x
container.RegisterCollection(typeof(INotificationHandler<>),
AppDomain.CurrentDomain.GetAssemblies());
// Simple Injector v2.x
container.RegisterManyForOpenGeneric(
typeof(INotificationHandler<>),
container.RegisterAll,
AppDomain.CurrentDomain.GetAssemblies());现在,简单注入器能够在请求时解析PingedHandler、PingedHandler2和GenericHandler:
container.GetAllInstances<INotificationHandler<Pinged>>();发布于 2015-01-12 21:25:39
更新
对于简单的InjectorVersion2.7,此功能现在是标准的,您不再需要下面所示的解决方法。
您缺少了那篇文章中描述的MultipleDispatchEventHandler的一个变体。接受基本逻辑并将其应用到抽象中确实会给出您期望的结果:
[Fact]
public void RegisterAll_Contravariant_Succeeds()
{
var container = new Container();
container.RegisterManyForOpenGeneric(
typeof(INotificationHandler<>),
(service, impls) => container.RegisterAll(service, impls),
AppDomain.CurrentDomain.GetAssemblies());
var handlersType = typeof(IEnumerable<INotificationHandler<Pinged>>);
var handlersCollection = (
from r in container.GetCurrentRegistrations()
where handlersType.IsAssignableFrom(r.ServiceType)
select r.GetInstance())
.Cast<IEnumerable<INotificationHandler<Pinged>>>()
.ToArray();
var result =
from handlers in handlersCollection
from handler in handlers
select handler;
Assert.Equal(3, result.Count());
}但是,使GenericHandler成为通用的可能更容易:
public class GenericHandler<TNotification> : INotificationHandler<TNotification>
where TNotification : INotification
{
public void Handle(TNotification notification) { }
}进行简单的登记
[Fact]
public void RegisterAll_WithOpenAndClosedGenerics_Succeeds()
{
var container = new Container();
var types = OpenGenericBatchRegistrationExtensions
.GetTypesToRegister(
container,
typeof(INotificationHandler<>),
AccessibilityOption.AllTypes,
AppDomain.CurrentDomain.GetAssemblies())
.ToList();
types.Add(typeof(GenericHandler<>));
container.RegisterAll(typeof(INotificationHandler<>), types);
var result = container.GetAllInstances<INotificationHandler<Pinged>>().ToList();
Assert.Equal(3, result.Count());
}https://stackoverflow.com/questions/27909866
复制相似问题