SimpleInjector如何为一个泛型实现注册多个开放的泛型接口



我正试图开始使用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);
            }
        }
    };
}

您正在将IEventPublisherIEventSubscriber注册为单独的单例。您将需要以这样或那样的方式重构代码。一种解决方案是将调解员的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);

相关内容

  • 没有找到相关文章

最新更新