|
Subject:
|
Delegate query
|
|
Posted By:
|
elwappo
|
Post Date:
|
6/3/2008 6:50:43 AM
|
Hi all, I've been playing around with writing my own event handlers and I've a query about the use of a delegate.
Basically, I've noticed you don't need to declare a delegate to handle an event, but you can delcare a public event with the same signature as a delegate (see Finished Event defined below). Can anyone explain if what I'm doing in declaring the event handler this way is incorrect or should I always use a delegate?
I'm slightly confused to what the differences are and if there's any performance/run-time differences. I've included an example below which uses both types of declaration. One just counts down and raises an event every 0.5 seconds (update - delegate declared) and then raises and finish event after 5 seconds (Finish - event declared).
Here's an example I've written an event handler using both using a delegate (UpdateTime) and an Event (Finished):
Public Class TimerState Public Delegate Sub UpdateTime(ByVal Countdown As Double) Public Event Finished(ByVal msg As String)
Public Event update As UpdateTime
Public Sub StartCountdown(ByVal Duration As Double, _ ByVal Increment As Double) Dim Start As Double = DateAndTime.Timer Dim ElapsedTime As Double = 0
Dim SoFar As Double = 0 Do While ElapsedTime < Duration If ElapsedTime > SoFar + Increment Then SoFar += Increment RaiseEvent update(SoFar) End If ElapsedTime = DateAndTime.Timer - Start Loop RaiseEvent Finished(ElapsedTime.ToString) End Sub
End Class
Then in the application I do this...
Public WithEvents mText As TimerState
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load Button1.Text = "Start" mText = New TimerState End Sub
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click mText.StartCountdown(5.0, 0.1) End Sub
Private Sub mText_UpdateComplete(ByVal msg As String) Handles mText.Finished TextBox2.Text = "Done. Time Elapsed=" + msg End Sub
Private Sub mText_UpdateTime(ByVal Countdown As Double) Handles mText.update TextBox1.Text += Countdown.ToString + "," End Sub
Your help in clearing up my confusion and differences would be grately appreciated....
|
|
Reply By:
|
planoie
|
Reply Date:
|
6/3/2008 9:31:21 AM
|
Your query piqued my interest so I did a little investigation to satisfy my curiosity.
It appears there is basically no difference between the two declaration techniques. I created this simple class:
Class Events
'Technique 1
Public Delegate Sub UpdateTime(ByVal Countdown As Double)
Public Event Event1 As UpdateTime
'Technique 2
Public Event Event2(ByVal Countdown As Double)
End Class
In technique 1 you are explicitly defining a delegate (which is compiled into a class derived from System.MulticastDelegate). In technique 2, the compiler is doing this for you. Take a look at the disassembled MSIL code for each:
//Technique 1
.class auto ansi sealed nested public UpdateTime
extends [mscorlib]System.MulticastDelegate
...
.event EventDefinitions.Events/UpdateTime Event1
//Technique 2
.class auto ansi sealed nested public Event2EventHandler
extends [mscorlib]System.MulticastDelegate
...
.event EventDefinitions.Events/Event2EventHandler Event2
Apart from names of objects, all the other code is identical.
The benefit of using a predefined delegate is that you can reuse that same delegate for multiple events. Otherwise, it seems there is no difference once the code is compiled.
-Peter compiledthoughts.com
|
|
Reply By:
|
elwappo
|
Reply Date:
|
6/3/2008 1:18:46 PM
|
Thanks for your response and explanation. Much appreciated.
I presume when you say you can reuse the same delegate for multiple events, it could be declared in a helper class and called when needed? I presume then, you can reuse my "Finished" Event, as you mention there is no difference in my two declarations. So:
Public Event Finished(ByVal msg As String) could also be reusable?
From reading articles online/in books, event handling/delegates are a simple process that is explained very badly...one simple, real world example would clear up alot of confusion for developers like me when having to write their own handlers for the first time.
|
|
Reply By:
|
planoie
|
Reply Date:
|
6/3/2008 3:47:56 PM
|
quote: Originally posted by elwappo
I presume when you say you can reuse the same delegate for multiple events, it could be declared in a helper class and called when needed?
Yes, you certainly can put your delegates in a reusable location. When I define delegates for something specific I usually keep them with the related functionality. But general use delegates would go into a generic delegates file in the project somewhere.
One important semantic here though: At least within the context of this conversion, you don't "call" a delegate. In this case we are defining delegates for purpose of defining event signatures. So you define an even on a class that matches that delegate signature. The class defining the event will eventually raise it. What you are really going is calling the "Invoke" method of a class (your delegate) that is derived from System.MulticastDelegate.
quote: I presume then, you can reuse my "Finished" Event, as you mention there is no difference in my two declarations.
The only reuse you can make of an event defined on a class is to raise that event more than once. The event is just a member of the class, no different than a property or method. You reuse the types that define them and, by extension, those members. So you can create many instances of a class that has methods and the event is part of it so it is available to use.
quote: From reading articles online/in books, event handling/delegates are a simple process that is explained very badly...
The problem I have found is that delegates are a tricky beast because they are used in different ways. As I've mentioned, a delegate is really just a class based on a specific type. However, because of the nature of the event driven model of .NET dealing with events is such a core aspect so there are language constructs that obfuscate the use of the delegate classes.
When we are dealing with class events we create "events" instead of creating explicit instances of a delegate class. Then instead of explicitly calling 'myEvent.Invoke(...)' we can call RaiseEvent myEvent() [VB] or just myEvent() [C#]. The need to think about events as class instances is abstracted away by the languages.
You can also use delegate instances as method callbacks. In this case they are treated more like data. In this case the data is a pointer to a method. You call that method like you call any other method, but instead of the method name you use the variable name of the delegate instance.
-Peter compiledthoughts.com
|
|
Reply By:
|
elwappo
|
Reply Date:
|
6/3/2008 5:04:05 PM
|
Peter, your post has certainly cleared up alot of the grey areas I had around the subject. So thank you.
I can certainly see how not getting semantics correct can lead to confusion of understanding the subject. I've come across developers who will loosely explain a subject without using the correct terminology which doesn't help. I now appreciate why you don't "call" a delegate, and that an event defined withhin a class is just a member of that class.
I'm now reading your blogs with great interest. Re-writing URL's (April 2008) is certainly an area I'm currently interested in.
I'm currently investigating the redevelopment of an ASP.NET health encyclopaedia (written by another developer who has left no documentation). It uses and needs friendly URLs. And from my investigation so far, .NET 2.0 doesn't support friendly URLs very well unless you intercept the initial HTTP request. I suppose it'll keep me away from delegates for a while... Kind Regards
|
|
Reply By:
|
planoie
|
Reply Date:
|
6/4/2008 9:05:01 AM
|
(Repost, brain fart.)
quote: Originally posted by elwappo
And from my investigation so far, .NET 2.0 doesn't support friendly URLs very well unless you intercept the initial HTTP request. I suppose it'll keep me away from delegates for a while...
Delegates and URL re-writing aren't interrelated such that you need one for the other.
Have you considered a standard Wiki application for your health encyclopedia? I have been using MediaWiki (the Wiki behind Wikipedia) and I've found it incredibly easy and fast (two tenets of Wikis).
-Peter compiledthoughts.com
|
|
Reply By:
|
elwappo
|
Reply Date:
|
6/5/2008 3:07:38 AM
|
Sorry, I was making a quip when I mentioned URL rewriting would keep me away from Delegates for a while!
I have to develop the Health Encyclopaedia as it needs to integrate within a current .NET website page. Plus the underlying data structure is more complex than a standard wiki would offer. Otherwise I would have considered a free wiki....
quote:
Delegates and URL re-writing aren't interrelated such that you need one for the other.
Have you considered a standard Wiki application for your health encyclopedia? I have been using MediaWiki (the Wiki behind Wikipedia) and I've found it incredibly easy and fast (two tenets of Wikis).
|