Raising Shared Events Chapters 8 and 9 explained dynamic programming afforded to us by events and event handlers, all falling under the auspices of the Delegate class. Keep in mind that RaiseEvent incurs no penalty if there are no respondents. If you write your code to invoke a specific method, at runtime you are stuck with the behavior described by that respondent. However, if you define an event and raise the event, any respondent can answer the event. Consider the revised code from Listing 11.9, shown in Listing 11.10, that demonstrates using a fixed respondent to indicate to the consumer of HasOverloaded that a Print method was invoked. (Parts of the original code from Listing 11.9 were concealed with code outlining to shorten the listing.) Caution Listing 11.10 demonstrates code that is too dependent on the existence of a specific form, Form1. Avoid writing code that relies on a specific object instance. Listing 11.10 A shared method talking to an instance of a form1: Public Class Form1 2: Inherits System.Windows.Forms.Form 3: 4: [ Windows Form Designer generated code ] 5: 6: Private Sub Button1_Click(ByVal sender As System.Object, _ 7: ByVal e As System.EventArgs) Handles Button1.Click 8: 9: HasOverloaded.Print("Hello World!") 10: [...] 11: 12: End Sub 13: 14: Public Sub Print(ByVal Value As Object) 15: Text = "Print: " & Value 16: End Sub 17: 18: Private Sub Form1_Load(ByVal sender As System.Object, _ 19: ByVal e As System.EventArgs) Handles MyBase.Load 20: 21: HasOverloaded.AForm = Me 22: 23: End Sub 24: 25: End Class 26: 27: Public Class HasOverloaded 28: 29: Public Shared AForm As Form1 30: 31: Overloads Shared Sub Print(ByVal Text As String) 32: AForm.Print(Text) 33: Debug.WriteLine(Text) 34: End Sub 35: 36: [...] 37: 38: End Class HasOverloaded uses a shared field, AForm on line 29, to obtain a reference to an instance of Form1. Form1's OnLoad event handler, defined on lines 18 through 23, initializes the shared reference in HasOverloaded. Functionally, and to a limited degree, this code works, but as a rule it's considered bad form. Although aggregation, inheritance, and references are a good thing in general, the reference to Form1 makes HasOverloaded brittle. In essence, the instance of the form breaches the invisible bubble of encapsulation, which should be avoided. Consider what happens to HasOverloaded if Form1 is destroyed . The Print method on line 31 is no longer valid. Again, what happens if Form1 is given a better name ? Again, HasOverloaded.Print (line 31) is invalid. A preferable alternative in this instance is to use a shared event to promote the interaction to the class interface level. The end result (shown in Listing 11.11) is valid code regardless of whether or not Form1 exists or is renamed because the interaction happens at the class interfacealong the edges described by the public membersinstead of inside the methods . Listing 11.11 Using a shared event to facilitate interactions with class methods1: Public Class Form1 2: Inherits System.Windows.Forms.Form 3: 4: [ Windows Form Designer generated code ] 5: 6: Private Sub Button1_Click(ByVal sender As System.Object, _ 7: ByVal e As System.EventArgs) Handles Button1.Click 8: 9: HasOverloaded.Print("Hello World!") 10: [...] 11: 12: End Sub 13: 14: Private Sub OnPrint(ByVal Value As Object) 15: Text = "OnPrint: " & Value 16: End Sub 17: 18: Private Sub Form1_Load(ByVal sender As System.Object, _ 19: ByVal e As System.EventArgs) Handles MyBase.Load 20: 21: AddHandler HasOverloaded.OnPrint, AddressOf OnPrint 22: 23: End Sub 24: 25: End Class 26: 27: Public Class HasOverloaded 28: 29: Public Shared Event OnPrint(ByVal Value As Object) 30: 31: Overloads Shared Sub Print(ByVal Text As String) 32: RaiseEvent OnPrint(Text) 33: Debug.WriteLine(Text) 34: End Sub 35: 36: [...] 37: 38: End Class The revised listing adds the handler Form1.OnPrint to the implicit Delegate defined by the shared event on line 29 in the HasOverloaded class. Line 32 simply raises the event and is indifferent to the specific recipients, or even if there are recipients. What you don't see is that the RaiseEvent statement on line 32 checks an invocation list and sends the event to respondents, but it works correctly whether there are respondents or not. An additional benefit of using the public Shared event is that other objects can implement OnPrint handlers and add themselves to the invocation list of the Delegate in HasOverloaded. This minor revision might seem trivial, but these small changes in implementation mean the difference between flexible, robust, and loosely coupled code (as in Listing 11.11) and brittle, unmanageable, and tightly coupled code (as in Listing 11.10). That is all the difference in the world. |
Team-Fly |
Top |