我正试图开始使用SimpleInjector作为IOC容器,到目前为止我对它非常满意。但现在我被一个我解决不了的问题困住了。我在SO和文档中搜索,但似乎还没有回答。我看过SimpleInjector的how - wto文档,但它没有涵盖开放的泛型接口。
我有两个这样的通用接口:
public interface IEventPublisher<TEvent>
{
void Publish(TEvent Event);
}
public interface IEventSubscriber<TEvent>
{
void Subscribe(Action<TEvent> CallBack);
}
和这两个的一个开放的通用实现:
class EventMediator<T> : IEventPublisher<T>, IEventSubscriber<T>
{
List<Action<T>> Subscriptions = new List<Action<T>>();
public void Publish(T Event)
{
foreach (var Subscription in this.Subscriptions)
Subscription.Invoke(Event);
}
public void Subscribe(Action<T> CallBack)
{
this.Subscriptions.Add(CallBack);
}
}
在我的应用程序中,我像这样设置SimpleInjector:
this.Container = new SimpleInjector.Container();
this.Container.RegisterOpenGeneric(typeof(IEventPublisher<>), typeof(EventMediator<>), Lifestyle.Singleton);
this.Container.RegisterOpenGeneric(typeof(IEventSubscriber<>), typeof(EventMediator<>), Lifestyle.Singleton);
this.Container.Verify();
我想归档的是:我想在请求一个IEventPublisher或一个IEventSubscriber时得到完全相同的实例。此外,这个实例应该是任何t的单例。
我用这些行测试了一下:
class DummyEvent {}
var p = this.Container.GetInstance<IEventPublisher<DummyEvent>>();
var s = this.Container.GetInstance<IEventSubscriber<DummyEvent>>();
var areSame = (object.ReferenceEquals(p,s));
不幸的是p和s不指向同一个实例。有人知道这个问题的解决方法吗?
对此有一定的解决方案,这里有一个:为IEventPublisher<T>
和IEventSubscriber<T>
创建单独的实现,并让它们委托给EventMediator<T>
。例如,使用这些实现:
public class EventPublisher<TEvent> : IEventPublisher<TEvent>
{
private readonly EventMediator<TEvent> mediator;
public EventPublisher(EventMediator<TEvent> mediator) {
this.mediator = mediator;
}
public void Publish(TEvent Event) {
this.mediator.Publish(Event);
}
}
public class EventSubscriber<TEvent> : IEventSubscriber<TEvent>
{
private readonly EventMediator<TEvent> mediator;
public EventSubscriber(EventMediator<TEvent> mediator) {
this.mediator = mediator;
}
public void Subscribe(Action<TEvent> CallBack) {
this.mediator.Subscribe(Callback);
}
}
现在按如下方式进行注册:
container.RegisterSingleOpenGeneric(typeof(EventMediator<>), typeof(EventMediator<>));
container.RegisterSingleOpenGeneric(typeof(IEventPublisher<>), typeof(EventPublisher<>));
container.RegisterSingleOpenGeneric(typeof(IEventSubscriber<>), typeof(EventSubscriber<>));
现在EventPublisher<DummyEvent>
和EventSubscriber<DummyEvent>
都指向同一个EventMediator<DummyEvent>
实例。
ResolveUnregisteredType
事件(这是RegisterOpenGeneric
扩展方法本身在幕后使用的)。您的配置看起来像这样:
container.RegisterSingleOpenGeneric(typeof(EventMediator<>), typeof(EventMediator<>));
container.ResolveUnregisteredType += (s, e) =>
{
if (e.UnregisteredServiceType.IsGenericType)
{
var def = e.UnregisteredServiceType.GetGenericTypeDefinition();
if (def == typeof(IEventPublisher<>) || def == typeof(IEventSubscriber<>))
{
var mediatorType = typeof(EventMediator<>)
.MakeGenericType(e.UnregisteredServiceType.GetGenericArguments()[0]);
var producer = container.GetRegistration(mediatorType, true);
e.Register(producer.Registration);
}
}
};
您甚至可以将此代码提取到更通用的扩展方法中。这样你的注册看起来就像这样:
container.RegisterSingleOpenGeneric(typeof(EventMediator<>), typeof(EventMediator<>));
container.ForwardOpenGenericTo(typeof(IEventPublisher<>), typeof(EventMediator<>));
container.ForwardOpenGenericTo(typeof(IEventSubscriber<>), typeof(EventMediator<>));
扩展方法看起来像这样:
public static void ForwardOpenGenericTo(this Container container,
Type openGenericServiceType, Type openGenericServiceTypeToForwardTo)
{
container.ResolveUnregisteredType += (s, e) =>
{
var type = e.UnregisteredServiceType;
if (type.IsGenericType)
{
if (type.GetGenericTypeDefinition() == openGenericServiceType)
{
var forwardToType = openGenericServiceTypeToForwardTo.MakeGenericType(
type.GetGenericArguments());
var producer = container.GetRegistration(forwardToType, true);
e.Register(producer.Registration);
}
}
};
}
您正在将IEventPublisher
和IEventSubscriber
注册为单独的单例。您将需要以这样或那样的方式重构代码。一种解决方案是将调解员的3个职责分开:
用户
public interface IEventSubscriber<TEvent>
{
void Subscribe(Action<TEvent> CallBack);
}
public class EventSubscriber<T> : IEventSubscriber<T>
{
public readonly ISubscriptions<T> subscriptions;
public EventSubscriber(ISubscriptions<T> subscriptions)
{
this.subscriptions = subscriptions;
}
public void Subscribe(Action<T> CallBack)
{
this.subscriptions.Add(CallBack);
}
}
public interface IEventPublisher<TEvent>
{
void Publish(TEvent Event);
}
public class EventPublisher<T> : IEventPublisher<T>
{
public readonly ISubscriptions<T> subscriptions;
public EventPublisher(ISubscriptions<T> subscriptions)
{
this.subscriptions = subscriptions;
}
public void Publish(T Event)
{
foreach (var subscription in this.subscriptions)
{
subscription.Invoke(Event);
}
}
}
订阅
public interface ISubscriptions<T> : IList<Action<T>> { }
public class Subscriptions<T> : List<Action<T>>, ISubscriptions<T> { }
只有订阅需要注册为单例
var container = new Container();
container.RegisterOpenGeneric(typeof(IEventSubscriber<>), typeof(EventSubscriber<>));
container.RegisterOpenGeneric(typeof(IEventPublisher<>), typeof(EventPublisher<>));
container.RegisterSingleOpenGeneric(typeof(ISubscriptions<>), typeof(Subscriptions<>));
container.Verify();
var p = container.GetInstance<IEventPublisher<DummyEvent>>();
var s = container.GetInstance<IEventSubscriber<DummyEvent>>();
Assert.That(
(p as EventPublisher<DummyEvent>).subscriptions ==
(s as EventSubscriber<DummyEvent>).subscriptions);