一般的な解決策は、ある種の pub/sub パターンを使用することです。そうすることで、循環依存を避けることができます。
基本的に、イベントをサブスクライブする (およびそれらを公開する) ために使用されるある種のクラスを作成します。
したがって、両方のクラスが次のようなことを行います (ただし、イベントは異なります)。
public class ClassA : IEventHandler<UserCreated>
{
IEventManager _eventManager
public ClassA(IEventManager manager)
{
// I subscribe on this event (which is published by the other class)
manager.Subscribe<UserCreated>(this);
_eventManager = manager;
}
public void Handle(UserCreated theEvent)
{
//gets invoked when the event is published by the other class
}
private void SomeInternalMethod()
{
//some business logic
//and I publish this event
_eventManager.Publish(new EmailSent(someFields));
}
}
イベント マネージャー (簡略化され、スレッド セーフではありません):
public class EventManager
{
List<Subscriber> _subscribers = new List<Subscriber>();
public void Subscribe<T>(IEventHandler<T> subscriber)
{
_subscribers.Add(new Subscriber{ EventType = typeof(T), Subscriber = subscriber});
}
public void Publish<T>(T theEvent)
{
foreach (var wrapper in subscribers.Where(x => x == typeof(theEvent)))
{
((IEventHandler<T>)wrapper.Subscriber).Handle(theEvent);
}
}
}
小さなラッパー:
public class Subscriber
{
public Type EventType;
public object Subscriber;
}
出来上がり。2 つのクラスは疎結合になりました (相互に通信することはできます)。
コントロール コンテナーの反転を使用すると、イベント マネージャーを単純化し、コンテナー (サービスの場所) を使用してすべてのサブスクライバーを解決できるため、より簡単になります。
public class EventManager
{
IYourContainer _container;
public EventManager(IYourContainer container)
{
_container = container;
}
public void Publish<T>(T theEvent)
{
foreach (var subscriber in _container.ResolveAll<IEventHandler<T>>())
{
subscriber.Handle(theEvent);
}
}
}