Hi JPRoot,
Ok, VC++ defines 3 accessors for events (for adding, removing and raising
the event).
*add* and *remove* accessors has the visibility which is specified for the
event when it is decalred. *Rise* accesor is almost always protected except
when the event is private then and *raise* accessor is private.
What does it mean?
That means that you don't have to do anything in C++ to inherit the base
event. So your code can be transformed to
namespace MyNamespace
{
public __delegate void MyDel();
public __gc class MyBase
{
public:
__event MyDel* MyEvent;
public:
void MyMethod2()
{
__raise MyEvent();
}
};
public __gc class MyDerived : public MyBase
{
public:
void MyMethod()
{
//This will raise the base class' event because raise_MyEvent
method is protected
__raise MyEvent();
}
};
public __gc class EventReceiver
{
public:
static void MyEventHandler()
{
System::Console::WriteLine("Event fired!");
}
};
};
int _tmain(void)
{
MyNamespace::MyDerived* aa = new MyNamespace::MyDerived();
MyNamespace::MyBase* bb = aa;
MyNamespace::MyDel* receiver = new MyNamespace::MyDel( 0,
MyNamespace::EventReceiver::MyEventHandler );
aa->MyEvent += receiver;
bb->MyEvent += receiver;
aa->MyMethod();
aa->MyMethod2();
MyNamespace::MyBase* cc = new MyNamespace::MyBase();
cc->MyEvent += receiver;
cc->MyMethod2();
System::Console::ReadLine();
return 0;
}
And this will work just perfectly.
This is not the case of C#, though. C# compiler doesn't generate *raise*
accessors for events and it inlines calls delegate's Invoke method whenever
it finds language constuction like DelegateMemberName(....).
For the sme line VC++ will generate call to raise_DelegateMemberName(....)
method.
Which means that VC++ programs cannot use classes written in C# because they
don't have raise_XXX methods defined as well as if you write the class
hierarchy as in the VC++ examples we discuss C# program will be able to use
the parent event only if the C# programmer knows about those raise_XXX
methods.
Who is wrong in this case. I'm really really confused.
If we look in CLI specification (Part I - Architecture) we can find:
Per 8.11.4 Event Definitions
The CTS supports events in precisely the same way that it supports
properties (see clause 8.11.3). The
conventional methods, however, are different and include means for
subscribing and unsubscribing to events as
well as for firing the event.
-------
C# doesn't generate method for *firing* the event.
Per 10.4 Naming Patterns
See also Partition V. 30
While the CTS does not dictate the naming of properties or events, the CLS
does specify a pattern to be
observed.
For Events:
An individual event is created by choosing or defining a delegate type that
is used to signal the event. Then,
three methods are created with names based on the name of the event and with
a fixed signature. For the
examples below we define an event named Click that uses a delegate type
named EventHandler.
EventAdd, used to add a handler for an event
Pattern: void add_<EventName> (<DelegateType> handler)
Example: void add_Click (EventHandler handler);
EventRemove, used to remove a handler for an event
Pattern: void remove_<EventName> (<DelegateType> handler)
Example: void remove_Click (EventHandler handler);
EventRaise, used to signal that an event has occurred
Pattern: void family raise_<EventName> (Event e)
------
C# creates only two names.
Per 8.10.3 Property and Event Inheritance
.....
The source compiler shall generate CIL that directly accesses the methods
named by the events and properties, not the events or properties themselves.
------
C# compiler doesn't use the method decalred for raising the event
And I finaly got lost in my confusion when I saw that no class of the
framework has raise_XXX method.
I have to confess that I haven't read the specs carefully so I might
misunderstood something.
Can anybody explain what CLI specification states and why only VC++
generates and uses *raise* methods?
Neither C# nor VB.NET do that
B\rgds
100
"JPRoot" <jp****@hotmail.com> wrote in message
news:B8**********************************@microsof t.com...
100,
You are 100% right.
The point I am trying to make is that the Add and Remove are made virtual
when you put the virtual keyword besides the event keyword but not the Raise
which I see as a bug(or lack of completeness of the feature) since in
VC++.NET Managed when you put the virtual keyword besides an __event not
only the Add and Remove becomes virtual but also the Raise method, which
makes complete sence!!
Other feature that C# lacks is a way to define the Raise method like you
can do in VC++.NET Managed.
Here's the exact same snippet I first posted but in VC++.NET Managed where
event "virtualization" really works!! Also, having it this way, makes it
useless to have OnXXX pattern... or at least less useful :)
#using <mscorlib.dll>
#include <tchar.h>
using namespace System;
namespace MyNamespace
{
__delegate void MyDel();
public __gc class MyBase
{
public:
virtual __event MyDel* MyEvent;
public:
void MyMethod2()
{ // this should call child class event if overriden
__raise MyEvent();
}
};
public __gc class MyDerived : public MyBase
{
protected:
__event MyDel* m_myEventInvokeList;
public:
virtual __event void add_MyEvent(MyDel* d)
{
m_myEventInvokeList += d;
}
virtual __event void remove_MyEvent(MyDel* d)
{
m_myEventInvokeList -= d;
}
protected:
virtual __event void raise_MyEvent()
{
__raise m_myEventInvokeList();
}
public:
void MyMethod()
{ // Raise event. Without the virtual/override keywords,
// child classes are not allowed to raise events declared
// in their base class
__raise MyEvent();
}
};
public __gc class EventReceiver
{
public:
static void MyEventHandler()
{
System::Console::WriteLine("Event fired!");
}
};
};
int _tmain(void)
{
MyNamespace::MyDerived* aa = new MyNamespace::MyDerived();
MyNamespace::MyBase* bb = aa;
MyNamespace::MyDel* receiver = new MyNamespace::MyDel( 0,
MyNamespace::EventReceiver::MyEventHandler ); aa->MyEvent += receiver;
bb->MyEvent += receiver;
aa->MyMethod();
aa->MyMethod2();
MyNamespace::MyBase* cc = new MyNamespace::MyBase();
cc->MyEvent += receiver;
cc->MyMethod2();
System::Console::ReadLine();
return 0;
}
----- 100 wrote: -----
Hi JPRoot,
IMHO this is indeed very strange way to use base class's events. And
beside I find it strange it is wrong or at least error prone.
You have to check the event for null before fire it because you can't
know if you have handlers registered for that event:
if(MyEvent != null) MyEvent();
But this is not the bigest flaw.
When you define an event as virtual actually you define its accessors
(add and remove) as virtual, but each class in the hierarchy will have its
own field of type *delegate void MyDel()* to hold the handlers
What does it means? Let me provide a new example.
public delegate void MyDel();
class Foo
{
public virtual MyDel MyEvent;
public FooRaiseMyEvent()
{
if(MyEvent != null) MyEvent();
}
}
class Bar: Foo
{
public override MyDel MyEvent;
public BarRaiseMyEvent()
{
if(MyEvent != null) MyEvent();
}
}
Now let we have the following code snippet
Foo foo = new Bar();
foo.MyEvent += new MyDel(foo_MyEvent);
Bar bar = (Bar) foo; //we can do that because the object is of
type Bar.
bar.BarRaiseMyEvent(); //Everything is just perfect the event fires
bar.FooRaiseMyEvent(); // Bar inherits this method from Foo, but no
event fires.
Which means that no methods form the base class can fire the event.
Imagine if you have more classes in the hierarchy....
Why is this happen?
Because doing
foo.MyEvent += new MyDel(foo_MyEvent);
we call MeEvent's *add* accessor polymorphically and the one decalred
in Bar will be called. It will add the handler to the delegate chain in
Bar's field of type MyDel.
Now when BarRaiseMyEvent calles MyEvent() it uses Bar's delegate
field, which has something inside.
FooRaiseMyEvent., though, uses Foo's delegate field which has nothing
inside and no event is fired.
Access to Fields cannot be polymorphical.
To use events declared in the base class use the design pattern used
throughout the framework (OnXXX methods).
I believe it is described somewhere in MSDN but I don't remember
where. Try to look at
ms-help://MS.MSDNQTR.2003FEB.1033/cpguide/html/cpconprovidingeventfunctional ity.htm
HTH
B\rgds
100
"JPRoot" <jp****@hotmail.com> wrote in message
news:0A**********************************@microsof t.com... > Hi,
> I use the following syntax to have events inherited from base to
child classes which works nicely (virtual and override keyword on events).
But I am wondering if it is a "supported" way of using events since I never
saw it used anywhere in MSDN documentation/samples?! Or it will just break
when I upgrade to .NET Framework 2.x in the coming years? >> namespace MyNamespace
> {
> public delegate void MyDel(); >> public class MyBase
> {
> public virtual event MyDel MyEvent;
> public void MyMethod2()
> {
> MyEvent();
> }
> } >> public class MyDerived : MyBase
> {
> // Override base class event so that it can
> // be raise from child (here!)
> public override event MyDel MyEvent; >> public void MyMethod()
> { // Raise event. Without the virtual/override keywords,
> // child classes are not allowed to raise events declared
> // in their base class
> MyEvent();
> }
> }
> } >> Thanks
> JPRoot
>