Tinkerforge/generators — pull request #15 by NobodysNightmare (2012-06-14 19:26:25+00:00)
Title: C#: Events for callbacks

A month ago I proposed with Issue #7 to do the callback-handling via .NET-Events.
Today I made the neccessary changes, as I needed them for my current application.

I will explain what I did, what the benefits are, which caveats there are and what I did not do in favour of better backwards-compatibility but could do in favour of the more natural .NET-Solution.

What does change?
==============
All device-callbacks (global enumerate callback excluded) are now accessable as events, this means attaching to the Temperature-callback of a Temperature-Bricklet now looks like this:
````
myBricklet.Temperature += MyCallback;
````
detaching a previously registered callback is also possible:
````
myBricklet.Temperature -= MyCallback;
````

For all other purposes usage is basically the same.

The old RegisterCallback-method still works, but is marked as Obsolete.

Benefits
======
- multiple handlers per callback are possible (this is extremely good with bricks like the Servo-Brick, where you might want to have one PositionReached-handler per servo, not per Servo-Brick)
- type-checking is done at compile-time (whereas RegisterCallback(...) can only do runtime-checking)
- It is the natural C#/.NET-Way of doing callbacks (the previous way is not intuitive)

Caveats
======
As the name of the Delegates needed to be changed, old Code will break here:
````
myBricklet.RegisterCallback(new BrickletHumidity.Humidity(WriteConsoleHumidity));
````
because the delegate is now called HumidityEventHandler.

Why was that neccessary?
I think I could have let the name "Humidity", but as this is the most senseful name for the Event itself there would have been great confusion to what BrickletHumidity.Humidity refers (programmer-confusion, for the compiler this should be unambigious).

Short story: This caveat could be eliminated, but the costs in terms of understandability of the code are quite high.

Another caveat is, that calling the RegisterCallback-method with an empty callback previously lead to the old callback being removed. As RegisterCallback now internally uses the event-mechanism this implementation-detail does not hold anymore.

In the end both caveats concern backwards-compatibility, I don't think that there are weaknesses besides that.

.NET-Conventions
=============
There are some conventions on raising events in .NET, link: http://msdn.microsoft.com/en-us/library/wkzf914z(v=vs.80).aspx

I did not follow all of them to ease code-migration, however you might say that it is worth to follow all of them, because its just worth it.

The conventions are basically:
1. The delegate should be named EventNameEventHandler
2. events should be raised from a protected method called OnEventName
3. The delegates should accept the parameters (object sender, EventNameEventArgs eventArgs)

I did obey point 1 and 2. Explanation for Point 2: This basically allows subclasses of a device to access the event without registering for it.

Point 3 would have lead to a massively breaking change, as all callback-handlers would have had to be changed (Whereas now you only need to update callback-registration). However, for the C-Bindings a user already requested to be able to connect Multiple IO-Bricklets to the same callback and to be able to tell, which Bricklet raised the callback. This is exactly the purpose of the sender-argument from the .NET-conventions.

Further Questions?
==============
If there are further questions regarding .NET-Events or regarding some decisions I made feel free to ask/discuss.

Side Note
--------------
This is the pure version of my last request, adapted to the latest (and much cleaner :) ) IPConnection-Code. It is free of any other changes, but realising callbacks as events.