Kai*_*Kai 6 c# generics open-generics simple-injector
我正在尝试使用SimpleInjector作为IOC容器,到目前为止我对此非常满意.但是现在我遇到了一个我无法解决的问题.我搜索了SO和文档,但似乎还没有回答.我已经看过SimpleInjector的howto doc但是它没有涵盖开放的通用接口.
我有两个这样的通用接口:
public interface IEventPublisher<TEvent>
{
void Publish(TEvent Event);
}
public interface IEventSubscriber<TEvent>
{
void Subscribe(Action<TEvent> CallBack);
}
Run Code Online (Sandbox Code Playgroud)
这两个开放的通用实现:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
在我的应用程序中,我正在设置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();
Run Code Online (Sandbox Code Playgroud)
我想要存档的是:在要求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));
Run Code Online (Sandbox Code Playgroud)
不幸的是,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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在您进行如下注册:
container.RegisterSingleOpenGeneric(typeof(EventMediator<>), typeof(EventMediator<>));
container.RegisterSingleOpenGeneric(typeof(IEventPublisher<>), typeof(EventPublisher<>));
container.RegisterSingleOpenGeneric(typeof(IEventSubscriber<>), typeof(EventSubscriber<>));
Run Code Online (Sandbox Code Playgroud)
现在无论是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);
}
}
};
Run Code Online (Sandbox Code Playgroud)
您甚至可以将此代码提取到更通用的扩展方法中.这样您的注册将如下所示:
container.RegisterSingleOpenGeneric(typeof(EventMediator<>), typeof(EventMediator<>));
container.ForwardOpenGenericTo(typeof(IEventPublisher<>), typeof(EventMediator<>));
container.ForwardOpenGenericTo(typeof(IEventSubscriber<>), typeof(EventMediator<>));
Run Code Online (Sandbox Code Playgroud)
扩展方法如下所示:
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);
}
}
};
}
Run Code Online (Sandbox Code Playgroud)