Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Best practice: Centralised event controller or not

I have an app which consists of several different assemblies, one of which holds the various interfaces which the classes obey, and by which the classes communicate across assembly boundaries. There are several classes firing events, and several which are interested in these events.

My question is as follows: is it good practice to implement a central EventConsolidator of some kind? This would be highly coupled, as it would need to know every class (or at least interface) throwing an event, and every consumer of an event would need to have a reference to EventConsolidator in order to subscribe.

Currently I have the situation where class A knows class B (but not C), class B knows class C, etc. Then if C fires an event B needs to pick it up and fire its own event in order for A to respond. These kinds of chains can get quite long, and it may be that B is only interested in the event in order to pass it along. I don't want A to know about C though, as that would break encapsulation.

What is good practice in this situation? Centralise the events, or grin and bear it and define events in each intermediate class? Or what are the criteria by which to make the decision? Thanks!

Edit: Here is another question asking essentially the same thing.

like image 736
Joel in Gö Avatar asked Nov 17 '08 08:11

Joel in Gö


2 Answers

You could put the event itself in an interface, so that A didn't need to know about C directly, but only that it has the relevant event. However, perhaps you mean that the instance of A doesn't have sight of an instance of C...

I would try to steer clear of a centralised event system. It's likely to make testing harder, and introduced tight coupling as you said.

One pattern which is worth knowing about is making event proxying simple. If B only exposes an event to proxy it to C, you can do:

public event FooHandler Foo
{
    add
    {
        c.Foo += value;
    }
    remove
    {
        c.Foo -= value;
    }
}

That way it's proxying the subscription/unsubscription rather than the act of raising the event. This has an impact on GC eligibility, of course - which may be beneficial or not, depending on the situation. Worth thinking about though.

like image 104
Jon Skeet Avatar answered Nov 15 '22 08:11

Jon Skeet


What you could try is using the event brokering of either NInject or the Unity Application Block.

This allows you to, for example:

[Publish("foo://happened")]
public event EventHandler<FooArgs> FooHappened;

[Subscribe("foo://happened")]
public void Foo_Happened(object sender, FooArgs args)
{ }

If both objects are created through the container the events will be hooked up automatically.

like image 40
Jonathan C Dickinson Avatar answered Nov 15 '22 06:11

Jonathan C Dickinson