What is the best way to implement chained events in C #

I have the following scenario. Client code has access only to FooHandler, and not directly to Foo instances.

public delegate void FooLoaded(object sender, EventArgs e); class Foo { public event FooLoaded loaded; /* ... some code ... */ public void Load() { load_asynchronously(); } public void callMeWhenLoadingIsDone() { loaded(this,EventArgs.Empty); } } class FooHandler { public event FooLoaded OneFooLoaded; /* ... some code ... */ public void LoadAllFoos() { foreach (Foo f in FooList) { f.loaded += new FooLoaded(foo_loaded); f.Load(); } } void foo_loaded(object sender, EventArgs e) { OneFooLoaded(this, e); } } 

Clients will then use the FooHandler class OneFooLoaded event to receive foos load notifications. Is this a "chain of events" right? Are there any alternatives? I don’t like it (this is wrong, I can’t say exactly why), but if I want the handler to be an access point, I do not seem to have many alternatives.

+6
c # events
source share
5 answers

If it doesn’t feel right, because the events are more complex and more appealing than what is necessary for internal messages (which, in my opinion, is at least partially true, given that events can cause several clients, then you know that you only need to notify about it, right?), then I propose the following alternative. Instead of using events to communicate the completion of Foo with FooHandler, since Foo is internal, you can add a callback parameter to the constructor or the Load Foo method that Foo can call when this is done at boot time. This parameter can be just a function if you have only one callback, or it can be an interface if you have a lot of them. Here, as I think, your code will look with a simplified backend:

 public delegate void FooLoaded(FooHandler sender, EventArgs e); class Foo { Action<Foo> callback; /* ... some code ... */ public void Load(Action<Foo> callback) { this.callback = callback; load_asynchronously(); } public void callMeWhenLoadingIsDone() { callback(this); } } class FooHandler { public event FooLoaded OneFooLoaded; /* ... some code ... */ public void LoadAllFoos() { foreach (Foo f in FooList) { f.Load(foo_loaded); } } void foo_loaded(Foo foo) { // Create EventArgs based on values from foo if necessary OneFooLoaded(this, null); } } 

Please note that this also allows you to more strictly print with the FooLoaded delegate.

If, on the other hand, he does not feel right, because the event does not have to go through FooHandler to get to the client, then 1) I would dispute this because if the client does not want to deal with the Foo person, he also should fire events at them at this level, and 2) If you really wanted to do this, you could implement some open callback interface on Foo, although Foo is private or use a mechanism similar to Pavel, I think, however, that customers like ease of implementation with less processing events and distinguishing the source within one handler, rather than the need to bind (and possibly disconnect) events from dozens of smaller objects.

+4
source share

Another way to do this is to create a single point (one class) in the domain where all the events take place. Any classes using the domain will connect to this class, which has a list of static events, and any internal class event in the domain will be listened to by this class, thereby avoiding at least the chain of events in the domain.

Literature:

+3
source share

A few tips that may or may not be useful ...

Write the event announcement as follows:

 public event FooLoaded loaded = delegate {}; 

This way you can safely run it, even if customers are not credited.

As for chain events, when you have two events:

 public event EventHandler a = delegate {}; public event EventHandler b = delegate {}; 

You may want shooting b to trigger shooting a:

 b += (s, e) => a(s, e); 

And then you can look at it and think that it would be more concise to say:

 b += a; 

Indeed, Resharper may even offer it to you! But that means something completely different. It adds the current contents of a to b , so if subsequent additional handlers exit with a , it will not cause them to be called when b starts.

+2
source share

I can tell you that such a waterfall of events is what I came to quite naturally several times, and I still have a serious problem with them.

Although I do not think that the events have ever passed transparently, but always with a semantic change. FooLoaded would become, for example, AllFoosLoaded . If you want to impose such a semantic change just for the sake of it, you can change OneFooLoaded to a percentage indicator (for example, should the receiving class know how much Foo ?).

I think that such constructions do not look right, because event intended for translation. He really does not impose a contract on the class that translates it, and does not impose a contract on the class that signs up for it.

Phase classes and general information hiding principles, however, are intended to facilitate the execution of contracts.

I'm still collecting my thoughts on this, sorry if the above is a bit unclear, but I don't know if there is a better way to do what you want. And if so, I am interested in seeing it as it is.

+1
source share

You can delegate add and remove in the event, and not raise:

 class FooHandler { public event FooLoaded OneFooLoaded { add { foreach (Foo f in FooList) { f.loaded += new FooLoaded(value); } } remove { foreach (Foo f in FooList) { f.loaded -= new FooLoaded(value); } } } public void LoadAllFoos() { foreach (Foo f in FooList) { f.Load(); } } } 

The above assumes that FooList is immutable for FooHandler . If it is changed, then you will also have to track the addition / removal of elements to it and add / remove handlers accordingly.

+1
source share

All Articles