Theoretical Event Trapping

JaedenRuiner

Well-known member
Joined
Aug 13, 2007
Messages
340
Programming Experience
10+
Yes, my title is a bit humorous, but to me so many things in vb.net are "theoretical" until I try them.

I've been working on a VERY generic class, abstract class that is, to handle certain collection based specifics I enjoy and don't want to have to rewrite. As part of my base class, the idea was to also generate certain events that would filter on through the ranks. My question is thus two fold, or sort of.

My initial idea is
BaseClass
AddFuncClass : inherits BaseClass
FinalClass: inherits AddFuncClass

Now BaseClass.OnEvent is Triggered, however AddFuncClass NEEDS to know when that Event is Fired, but it doesn't want to prevent FinalClass from knowing it was fired as well.

Thus I have:
VB.NET:
Expand Collapse Copy
AddFuncClass
------------
private sub BaseClassEvent() handles me.OnEvent
end sub

But the question is can AddFuncClass re-raise the OnEvent? and subsequently have FinalClass receive the event too, after AddFuncClass has processed it? Or can I do something like this:
VB.NET:
Expand Collapse Copy
AddFuncClass 
protected overridable sub BaseClassEvent() handles me.OnEvent
end sub

FinalClass
Protected Overrides sub BaseClassEvent() handles me.OnEvent
mybase.BaseClassEvent()
end sub

Or finally yet, Do i have to basically add intermediary events to AddFuncClass. Basically BasicClass triggers AddFuncClass, which triggers a whole new event for finalclass to trap.

Thanks
Jaeden "Sifo Dyas" al'Raec Ruiner
 
This sample follows the guidelines set for events usage pattern in class library development:
VB.NET:
Expand Collapse Copy
Class aBase
    Public Event TheEvent As EventHandler
    Protected Overridable Sub OnTheEvent(ByVal e As EventArgs)
        RaiseEvent TheEvent(Me, e)
        MsgBox("aBase knows")
    End Sub
    Public Sub raiser()
        OnTheEvent(New EventArgs)
    End Sub
End Class

Class Inh1Base
    Inherits aBase
    Protected Overrides Sub OnTheEvent(ByVal e As System.EventArgs)
        MsgBox("inh1Base knows")
        MyBase.OnTheEvent(e)
    End Sub
End Class

Class inh2Base
    Inherits Inh1Base
    Protected Overrides Sub OnTheEvent(ByVal e As System.EventArgs)
        MyBase.OnTheEvent(e)
        MsgBox("inh2Base knows")
    End Sub
End Class
An overriding element is implicitly overridable. You may do class specific event handling before or after calling the base implementation.

Example usage:
VB.NET:
Expand Collapse Copy
Private WithEvents a As New inh2Base

Private Sub test()
    a.raiser()
End Sub

Private Sub a_TheEvent(ByVal sender As Object, ByVal e As System.EventArgs) Handles a.TheEvent
    MsgBox("I know")
End Sub
 
Okay. I thought of that too. But I have a problem, and perhaps there just is no way around this.

In VB there is a Type defined as:
EventHandler(Of TEventArgs as EventArgs)

you can very easily create a descendant of EventArgs and then define a variable as such
VB.NET:
Expand Collapse Copy
public class MyCla(Of TArgs)
  Protected Event OnClear As EventHandler(Of TArgs)

  Public Sub DoSomething()
    Blah()
    OnClearEvent(me, New TArgs())
  end sub
Naturally assume that TArgs has a New() sub defined, and what not. But you get the idea. Using the EventHandler(Of TEventArgs) methodology, if you make your event follow the pattern:
OnName
the handler will implicitly declare a function
OnNameEvent(sender as object, e as TArgs)
which is great...but given the former strategy you've declared, I can't override OnNameEvent() in the subsequent inheriting objects.

thus
VB.NET:
Expand Collapse Copy
  Protected Event OnClear As EventHandler(Of TArgs)

  Protected Overrides Sub OnClearEvent(ByVal sender As Object, ByVal e As EventArgs)

  End Sub
causes 2 errors:
1 - Can't override because "Not Overridable"
2 - Can't override/shadow because predecessor is declared private.

So. Is there a way to get around this, or do I have to define my delegates manually instead of using the EventHandler(Of X) methodology.

Thanks
Jaeden "Sifo Dyas" al'Raec Ruiner
 
MyCla(Of TArgs) is generics, not inheritance. Did you misunderstand this or take logic shortcuts I didn't follow? Anyway, lets follow this just for fun; TArgs is in this case a "generic type holder" and not a defined type. You can't do "New TArgs", but have to use reflection to create a generic instance. EventHandler(Of TArgs) expression requires TArgs to be a type, which TArgs isn't. (It also requires a type that inherits EventArgs, but that's beside the point.) You can however define the event like this and let the compiler create a hidden delegate:
VB.NET:
Expand Collapse Copy
Public Event TheEvent(ByVal sender As Object, ByVal e As TArgs)
An inherited class will have no problem with this generic type holder because it would have to declare the same generics itself:
"Inherits MyCla" is not valid, "Inherits MyCla(Of Targs)" is, consequently the inherited class would have to be generic also to define this type holder:
VB.NET:
Expand Collapse Copy
Class ChildMyCla(Of TArgs)
Inherits MyCla(Of Targs)

End Class
So let's look at a full sample using same pattern as before, the classes:
VB.NET:
Expand Collapse Copy
Class AnotherBase(Of TArgs)
    Public Event TheEvent(ByVal sender As Object, ByVal e As TArgs)
    Protected Overridable Sub OnTheEvent(ByVal e As TArgs)
        RaiseEvent TheEvent(Me, e)
    End Sub
    Public Sub raiser()
        Dim x As TArgs = Activator.CreateInstance(Of TArgs)()
        MsgBox("AnotherBase knows")
        OnTheEvent(x)
    End Sub
End Class

Class ChildAnotherBase(Of TArgs)
    Inherits AnotherBase(Of TArgs)
    Protected Overrides Sub OnTheEvent(ByVal e As TArgs)
        MyBase.OnTheEvent(e)
        MsgBox("ChildAnotherBase knows")
    End Sub
End Class
sample usage:
VB.NET:
Expand Collapse Copy
Class someEventArgs
    Inherits EventArgs
End Class

Private WithEvents x As New ChildAnotherBase(Of someEventArgs)

Private Sub test()
    x.raiser()
End Sub

Private Sub x_TheEvent(ByVal sender As Object, ByVal e As someEventArgs) Handles x.TheEvent
    MsgBox("I know")
End Sub
Notice the code editor generated the correct x_TheEvent handler signature based on the generic type specifier given for ChildAnotherBase constructor.

While possible, I don't think this is good usage of generics, because you lock the classes to this "side type", this single events argument type is beside the point of the class (and its inheritors). A class usually has many events and each may have different type event args, so it's more or less pointless to set this as only possible generic parameter of the class that holds the event. Still here? And how would you handle the different eventarg members in the class? Reflection? (urrgh) Interface? (pointless)
 
MyClass(Of TArgs) is generics, not inheritance. Did you misunderstand this or take logic shortcuts I didn't follow?

Well,

Basically, I operate so much in theory of code all the time, I don't worry about the downrange specifics. that is what a compiler and syntax checker is for. Approach, breakdown, and execution are my methods. Every language is fundamentally the same, the only difference is grammer and syntax. This being said, I don't always formulate my questions with a pension for specifics, but for the concepts, and often expect others to assume I know the specifics.

Anyway, lets follow this just for fun; TArgs is in this case a "generic type holder" and not a defined type. You can't do "New TArgs", but have to use reflection to create a generic instance.

To point out all the intrinsic details would take more space than this forum would allow me to post, so to be brief, I've created a typeless collection manager, to handle many of my own specific idiosyncracies when it comes to languages and object models. Three main classes: HashListClass (basically a KeyedCollection), THash_Item (Note: No "_" in there, but the Language filter had a problem with the sh and it next to each other. *snicker*), and THashKey. All three are Abstract classes, and thus allow me to in one moment create an entire list class to behave exactly the way I want by overriding three classes and at best two methods each. I like things to work the way I want them, an most times that means writing it myself, but in situations like this it is ever so helpful to derive from KeyedCollection(of TKey, TItem). However I LIKE the generic typing. I don't have to use a Generic OBJECT type, but I can create type specific lists at the moment i desire to actual implement the current list, without having to replicate all the back end code each time. Seeing how the (Of Type) concept worked I probably went a bit overboard, but I had fun and the list algorthm is flawless.

Anyway, forgetting all of that.

These are the headers for the classes:
VB.NET:
Expand Collapse Copy
Public MustInherit Class HashListClass( _
    Of TData, THash, _
       TKey As THashKey, _
       TItem As THash_Item(Of TData, THash, TKey, TItem), _
       TArgs As THashListEventArgs(Of TKey, TItem, TArgs) _
  )
  Inherits System.Collections.ObjectModel.KeyedCollection(Of TKey, TItem)

Public MustInherit Class THash_Item( _
    Of TData, _
    THash, _
    TKey As THashKey, _
    TSelf As THash_Item(Of TData, THash, TKey, TSelf) _
  )

Public Class THashListEventArgs( _
    Of TKey, _
    TItem, _
    TSelf As THashListEventArgs(Of TKey, TItem, TSelf) _
  )
  Inherits EventArgs

public class THashKey
It looks convoluded and confusing i'm sure, especially without the underlying code, but the kick is this:
VB.NET:
Expand Collapse Copy
Public Class MultiDimensionCollection(Of TData)
  Inherits HashListClass(Of TData, Integer, MultiDimKey, MultiDimItem(Of TData), MultiDimEventArgs(Of TData))

Public Class MultiDimKey
  Inherits THashKey

Public Class MultiDimItem(Of TData)
  Inherits THash_Item(Of TData, Integer, MultiDimKey, MultiDimItem(Of TData))

Public Class MultiDimEventArgs(Of TData)
  Inherits THashListEventArgs(Of MultiDimKey, MultiDimItem(Of TData), MultiDimEventArgs(Of TData))

Now I can make a multi dimensional list of whatever type I want. I can create: MyStringGrid : inherits MultiDimensionCollection(Of String) and all the internal handlings are already built in, and just as easily i can change the inheritance type to be of Integer, or of TMyNewClassType() that does whatever I want.

But this is just the back story, so you can see i've just taken the logic and try to push it as far as it will go. The fun part of coding in my mind.

EventHandler(Of TArgs) expression requires TArgs to be a type, which TArgs isn't. (It also requires a type that inherits EventArgs, but that's beside the point.) You can however define the event like this and let the compiler create a hidden delegate:
VB.NET:
Expand Collapse Copy
Public Event TheEvent(ByVal sender As Object, ByVal e As TArgs)
An inherited class will have no problem with this generic type holder because it would have to declare the same generics itself:
"Inherits MyCla" is not valid, "Inherits MyCla(Of Targs)" is, consequently the inherited class would have to be generic also to define this type holder:
VB.NET:
Expand Collapse Copy
Class ChildMyCla(Of TArgs)
Inherits MyCla(Of Targs)

End Class
Quite right. That was the point of my question. Given the Built in Eventhandler(of TEventArgs) I could make event handler delegates all based upon the TArgs Passed Generic type, so that in the inheriting descendants They would define their own descendant event args types based upon the THashListEventArgs. The TSelf type parameter allows also my own idiosyncratic method of handling the whole event args type with event triggering and trapping.
VB.NET:
Expand Collapse Copy
Public Class THashListEventArgs( _
    Of TKey, _
    TItem, _
    TSelf As THashListEventArgs(Of TKey, TItem, TSelf) _
  )
  Inherits EventArgs

  public overridable function Init(byval ParamArray Args() As Object) as TSelf
    Return Me
  end function
end class

class otherclass(of TArgs as THashListEventArgs)
  Protected f_Args As New THashListEventArgs(Of TKey, TItem, TArgs)()  'This was taken from the defined classes above

  sub overridable OnMyEvent()
    RaiseEvent MyEvent(me, f_Args.Init(parameters))
  end sub
end class

This allows me to create one variable for all my event argument needs, and i can also maintain handling response fields in the eventargs type to determine if the item was to be removed, or inserted, or change its index, etc. I'm a big proponent of design something once to work for everything. (of course i recognize that as a statistical impossibility, but if one must have delusions, they should be of grandeur. *smile*)
So the idea, ow is that the descendant classes can manipulate the events, to their own ends, but the handling is universal. I wanted to trap the events in the underlying descendant classes, because MultiDimensionCollection requires two indexes, not one, and thus would need to reformat the Insert and remove events appropriately, since the unidirectional Index is not enough.

However, the question I needed to find out was if in the creation of the event, it appears I am forced to create my own delegate type, and thus have no use of the EventHandler(of TArgs) since, from what you've posted, The OnMyEvent() method is IMPLICITLY declared. I was trying to find out if there was a way to override that implicit declaration so that I don't have to define it in my base class. As it is, the only solution is to create the delegate.

so thus I must do this:
VB.NET:
Expand Collapse Copy
class baseclass
  public delegate sub HashListEventHandler(sender as object, e as TArgs)

  public OnClear as HashListEventHandler

  protected overridable sub OnClearEvent()
  end sub
end class

class subclass
  protected overrides sub OnClearEvent()
  end sub
end class
This method is fine, i was just trying to see how versatile the implicit declarations were. *shrug*.

Anyway, thanks for the help. :)
Jaeden "Sifo Dyas" al'Raec Ruiner
 
I see, you knew more than I first had the impression of :) I had a slight short last night and stated "the only possible generic parameter of the class", which is very wrong of course, the generic Of clause is a type list. Still TArgs is generic and have limited functionality when the implementation of the class needs to access its members. Generics benefits most from when class only needs to treat the generic type as an Object, typically for managing collections of this type. So what benefit would a TArgs have when its class members doesn't matter? If you look at the source code for generic .Net classes you will see they never access class members of the T object, that is what generic typeless classes implicitly means, what type it is is of no concern to the class. An event parameter type that has no members is the EventArgs class.
from what you've posted, The OnMyEvent() method is IMPLICITLY declared
No, the delegate is implicitly declared when you use the Event keyword.
 
Well, the fog is finally starting to clear here, and I think I'm seeing what you want to do from the theoretical to practical perspective, and I also learned something new about generics, not bad at all for a Thursday! So your intension was to write a generic base class to be implemented by specific inheritors which was not generic. It didn't shine very strong through from all the classes you posted, which also had lots of confusing and abstract details and generic parameters, but let me try again with the very simple base+child class example I started with and see if this makes sense to you also, first the generic base that carries an event that allows any type parameter:
VB.NET:
Expand Collapse Copy
Public MustInherit Class TheBase(Of TArgs)
    Public Event TheEvent(ByVal sender As Object, ByVal e As TArgs)
    Protected Overridable Sub OnTheEvent(ByVal e As TArgs)
        RaiseEvent TheEvent(Me, e)
    End Sub
End Class
any EventArgs class defined by class implementer (inheritor):
VB.NET:
Expand Collapse Copy
Public Class someEventArgs
    Inherits EventArgs
    Private newPropertyValue As Integer
    Public Property NewProperty() As Integer
        Get
            Return newPropertyValue
        End Get
        Set(ByVal value As Integer)
            newPropertyValue = value
        End Set
    End Property
End Class
then the inherited class that sets the score, making the generic base class into specific type child, with full knowledge and access to the type specific eventargs class:
VB.NET:
Expand Collapse Copy
Public Class ChildOfTheBase
    Inherits TheBase(Of someEventArgs) '<<< specific type implementation
    Protected Overrides Sub OnTheEvent(ByVal e As someEventArgs)
        MyBase.OnTheEvent(e)
    End Sub
    Public Sub raiserchild()
        Dim arg As New someEventArgs
        arg.NewProperty = 123
        OnTheEvent(arg)
    End Sub
End Class
finally end user sample:
VB.NET:
Expand Collapse Copy
Private WithEvents x As New ChildOfTheBase

Private Sub test()
    x.raiserchild()
End Sub

Private Sub x_TheEvent(ByVal sender As Object, ByVal e As someEventArgs) Handles x.TheEvent
    MsgBox("event raised, " & e.NewProperty.ToString)
End Sub
In light of this perspective it makes much sense what you are doing and also good usage of generics.
 
Back
Top