6

我正在尝试将 SimpleInjector 作为 IOC 容器开始使用,到目前为止我对它非常满意。但是现在我被困在一个我无法解决的问题上。我在 SO 和文档中进行了搜索,但似乎还没有答案。我已经看过SimpleInjector 的 howto 文档,但这不包括开放的通用接口。

我有两个像这样的通用接口:

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 时获得完全相同的实例。此外,这个 Instance 应该是任何 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 不是指同一个实例。有人碰巧知道这个问题的解决方案吗?

4

2 回答 2

5

有一些解决方案,这里有一个:为和创建单独的实现,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);
            }
        }
    };
}
于 2014-06-27T14:34:00.530 回答
3

您正在注册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);
于 2014-06-27T13:59:58.993 回答