C #: events or observer interface? Pros and cons?

I have the following (simplified):

interface IFindFilesObserver { void OnFoundFile(FileInfo fileInfo); void OnFoundDirectory(DirectoryInfo directoryInfo); } class FindFiles { IFindFilesObserver _observer; // ... } 

... and I do not agree. This is basically what I would write in C ++, but there are events in C #. Should I change the code to use events or leave it alone?

What are the advantages or disadvantages of events over the traditional observer interface?

+51
c # events observer-pattern
Feb 15 '09 at 12:10
source share
11 answers

Consider the event as a callback interface, where the interface has only one method.

Use only the events you need
With events, you only need to implement handlers for events that you are interested in handling. In the observer interface template, you need to implement all methods in the entire interface, including implementing method bodies for notification types that you really do not need. In your example, you always need to implement OnFoundDirectory and OnFoundFile, even if you only need one of these events.

Less maintenance
Another good thing about events is that you can add a new one to a particular class so that it raises it, and you do not need to change every existing observer. If you want to add a new method to an interface, you need to go around all the classes that already implement this interface and implement the new method in all of them. However, with an event, you only need to modify the existing classes that actually want to do something in response to the new event that you are adding.

The template is built into the language so that everyone knows how to use it
Events are idiomatic because when you see an event, you know how to use it. With the observer interface, people often implement various registration methods for receiving notifications and connecting the observer .. with events, although as soon as you learn to register and use one (with the + = operator), the rest are the same.

Benefits for Interfaces
I have not many advantages for interfaces. I assume that they force someone to implement all the methods in the interface. But you cannot force someone to correctly implement all of these methods, so I don’t think that this is of great value.

Syntax
Some people don't like how you should declare a delegate type for each event. In addition, standard event handlers in the .Net infrastructure have the following parameters: (object sender, EventArgs arguments). Since the sender does not specify a specific type, you must use it if you want to use it. This is often the case in practice if you are not feeling quite right because you are losing the protection of a static type system. But, if you implement your own events and don’t follow the .Net framework convention, you can use the correct type, so potential downstream casting is not required.

+61
Feb 15 '09 at 12:35
source share

Hmm, events can be used to implement the Observer pattern. In fact, the use of events can be seen as another implementation of the imho observer pattern.

+29
Feb 15 '09 at 12:14
source share

Advantages of the solution interface:

  • If you add methods, existing observers must implement these methods. This means that you are less likely to forget to connect existing observers to new features. You can, of course, implement them as empty methods, which means that you have the luxury of still not doing anything in response to certain “events”. But you will not easily forget.
  • If you use an explicit implementation, you will also get compiler errors; if you delete or modify existing interfaces, then the observers implementing them will stop compiling.

Minuses:

  • More attention should be paid to planning, as changing the observer interface can lead to changes in your entire decision, which may require other planning. Since a simple event is optional, little or no other code should change if another code does not respond to the event.
+7
Feb 15 '09 at 12:40
source share

Some additional benefits of events.

  • You get the correct multicast behavior for free.
  • If you change event subscribers in response to this event, the behavior is clearly defined
  • They can be easily and consistently investigated (reflected)
  • Tool chain support for events (simply because they are an idiom in .net)
  • You get the opportunity to use the asynchronous apis that it provides

You can achieve all of these (except the tool chain) yourself, but it is surprisingly difficult. For example: If you use a member variable as List <> to store a list of watchers. If you use foreach to iterate over it, any attempt to add or remove a subscriber in one of the OnFoo () method callbacks will throw an exception if you do not write additional code to handle it cleanly.

+6
Feb 15 '09 at 19:14
source share
  • Events are more difficult to propagate through a chain of objects, for example, if you use the FACADE template or delegate the work to another class.
  • You need to be very careful when unsubscribing from events so that the object can be garbage collected.
  • Events are 2 times slower than a simple function call, 3 times slower if you perform a zero check on each raise and copy the event delegate before a zero check and call to make it thread safe.

  • Also read MSDN about the new (in 4.0) IObserver<T> interface.

Consider the following example:

 using System; namespace Example { //Observer public class SomeFacade { public void DoSomeWork(IObserver notificationObject) { Worker worker = new Worker(notificationObject); worker.DoWork(); } } public class Worker { private readonly IObserver _notificationObject; public Worker(IObserver notificationObject) { _notificationObject = notificationObject; } public void DoWork() { //... _notificationObject.Progress(100); _notificationObject.Done(); } } public interface IObserver { void Done(); void Progress(int amount); } //Events public class SomeFacadeWithEvents { public event Action Done; public event Action<int> Progress; private void RaiseDone() { if (Done != null) Done(); } private void RaiseProgress(int amount) { if (Progress != null) Progress(amount); } public void DoSomeWork() { WorkerWithEvents worker = new WorkerWithEvents(); worker.Done += RaiseDone; worker.Progress += RaiseProgress; worker.DoWork(); //Also we neede to unsubscribe... worker.Done -= RaiseDone; worker.Progress -= RaiseProgress; } } public class WorkerWithEvents { public event Action Done; public event Action<int> Progress; public void DoWork() { //... Progress(100); Done(); } } } 
+6
Mar 27 '12 at 8:12
source share

The pluses are that events are more than dot-netty. If you are developing non-visual components that can be dropped onto a form, you can connect them using the constructor.

The downside is that an event means only one event - for each thing you need a separate event, which you want to notify the observer about. This has practically no great practical effect, except that each observed object will have to contain a link for each observer for each event, bloated memory in the case when there are many observed objects (one of the reasons why they made another way to control the observables / observable relationships in WPF).

In your case, I would say that it does not really matter. If the observer will usually be interested in all of these events, use the observer interface, not individual events.

+3
Feb 15 '09 at 12:18
source share

Java has language support for anonymous interfaces, so callback interfaces are what you need to use in Java.

C # has support for anonymous delegates - lambdas - and therefore events can be used in C #.

+2
Feb 15 '09 at 14:36
source share

The advantage of interfaces is that it is easier for them to use decorators. Standard example:

 subject.RegisterObserver(new LoggingObserver(myRealObserver)); 

compared with:

 subject.AnEvent += (sender, args) => { LogTheEvent(); realEventHandler(sender, args); }; 

(I am a big fan of decorator's drawing).

+2
Oct 27 2018-10-27
source share

I prefer the event database solution for the following reasons.

  • This reduces the cost of entry. It's much easier to say "+ = new EventHandler" than to implement a full-fledged interface.
  • This reduces maintenance costs. If you add a new event to your class, all you need to do. If you add a new event to the interface, you must update each individual user in the code base. Or define a completely new interface that over time becomes annoying for consumers. "Am I implementing IRandomEvent2 or IRandomEvent5?"
  • Events allow handlers to be non-class (i.e. a static method somewhere). There is no functional reason to force all event handlers to be a member of an instance.
  • Grouping event bundles in an interface makes an assumption about how events are used (and this is exactly that assumption)
  • Interfaces have no real advantage over a raw event.
+1
Feb 15 '09 at 14:32
source share

The best way to solve this is: which is best for the situation. This may sound like a stupid or useless answer, but I don’t think you should consider this or that as the “right” solution.

We can throw you a hundred tips. Events are best when the observer expects listening to arbitrary events. An interface is best when it is expected that an observer will be specified in the entire specified set of events. Events are best suited for GUI applications. Interfaces consume less memory (one pointer to several events). Poison poison poison. A bulleted list of pros and cons is what you need to think about, but not the final answer. What you really need to do is try both of them in real applications and get a good idea of ​​them. Then you can choose the one that best suits the situation. Examine the form.

If you need to use one definitive question, ask yourself what best describes your situation: a set of loosely coupled events, any of which can be used or ignored, or a set of closely related events that are usually handled by one observer. But then I just describe the event model and the interface model, so I will return to the square: which one is better suited?

+1
Feb 15 '09 at 17:05
source share

If your objects need to be serialized in some way that preserves links like NetDataContractSerializer or perhaps protobuf events will not be able to cross the border of serialization. Since the observer pattern is based only on object references, it can work with this type of serialization without problems if that is what you need.

Ex. You have a bunch of business objects that are bidirectionally linked to each other, which you need to pass to the web service.

0
Mar 17 '11 at 17:09
source share



All Articles