473,757 Members | 2,284 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Virtual Event doesn't behave as expected.

Hi,

when I run the following code:

using System;

namespace ConsoleApplicat ion22
{
class Program
{
static void Main(string[] args)
{
BaseClass baseClass = new BaseClass();
BaseClass inheritedBaseCl ass = new InheritedClass( );
InheritedClass inheritedClass = new InheritedClass( );
baseClass.Event A += new EventHandler(ba seClass_EventA) ;
inheritedBaseCl ass.EventA += new
EventHandler(in heritedBaseClas s_EventA);
inheritedClass. EventA += new
EventHandler(in heritedClass_Ev entA);
Console.ReadLin e();
}

static void inheritedClass_ EventA(object sender, EventArgs e)
{
throw new Exception("The method or operation is not
implemented.");
}

static void inheritedBaseCl ass_EventA(obje ct sender, EventArgs
e)
{
throw new Exception("The method or operation is not
implemented.");
}

static void baseClass_Event A(object sender, EventArgs e)
{
throw new Exception("The method or operation is not
implemented.");
}
}

class BaseClass
{
public virtual event EventHandler EventA
{
add
{
this.EventB += this.BaseClass_ EventB;
this.EventC += this.BaseClass_ EventC;
}

remove
{
this.EventC -= this.BaseClass_ EventC;
this.EventB -= this.BaseClass_ EventB;
}
}

public virtual event EventHandler EventB;

public virtual event EventHandler EventC
{
add
{
}
remove
{
}
}

void BaseClass_Event C(object sender, EventArgs e)
{
throw new Exception("The method or operation is not
implemented.");
}

void BaseClass_Event B(object sender, EventArgs e)
{
throw new Exception("The method or operation is not
implemented.");
}
}

class InheritedClass : BaseClass
{
public override event EventHandler EventB
{
add
{
Console.WriteLi ne("EventB: Override add called");
}

remove
{
Console.WriteLi ne("EventB: Override remove called");
}
}

public override event EventHandler EventC
{
add
{
Console.WriteLi ne("EventC: Override add called");
}
remove
{
Console.WriteLi ne("EventC: Override remove called");
}
}
}
}
Then only the override of EventC will be called, not the one from
EventB. Was this to be expected?

Thx Karsten

Mar 16 '07 #1
8 1612
It looks like the compiler is treating "EventB" as the
compiler-provided field, not the property; this only happens within
the actual class, not sub-classes. A poor workaround is to provide
your own backing field - then later references to "EventB" mean the
event and not the field:

private EventHandler _eventB;
public virtual event EventHandler EventB {
add { _eventB += value; }
remove { _eventB -= value; }
}

The better option is (depending on usage) to rationalise how how call
events, and rather than subscribing people to events they weren't
asking for, trigger the necessary event in the typical protected
virtual On... method.

protected override OnEventA() {
base.OnEventA() ;
OnEventB();
OnEventC();
}

Marc
Mar 16 '07 #2
Full code:

private EventHandler _eventB;
public virtual event EventHandler EventB {
add { _eventB += value; }
remove { _eventB -= value; }
}/*Hi,

when I run the following code:
*/
using System;

namespace ConsoleApplicat ion22
{
class Program
{
static void Main(string[] args)
{
BaseClass baseClass = new BaseClass();
BaseClass inheritedBaseCl ass = new InheritedClass( );
InheritedClass inheritedClass = new InheritedClass( );

baseClass.Event A += new EventHandler(ba seClass_EventA) ;
baseClass.Event B += new EventHandler(ba seClass_EventB) ;
inheritedBaseCl ass.EventA += new
EventHandler(in heritedBaseClas s_EventA);
inheritedBaseCl ass.EventB += new
EventHandler(in heritedBaseClas s_EventB);
inheritedClass. EventA += new
EventHandler(in heritedClass_Ev entA);
inheritedClass. EventB += new
EventHandler(in heritedClass_Ev entB);

baseClass.Foo() ;
inheritedBaseCl ass.Foo();
inheritedClass. Foo();

Console.ReadLin e();
}
static void inheritedClass_ EventB(object sender, EventArgs e)
{
Console.WriteLi ne("inheritedCl ass_EventB");
}
static void inheritedBaseCl ass_EventB(obje ct sender, EventArgs
e) {
Console.WriteLi ne("inheritedBa seClass_EventB" );
}
static void baseClass_Event B(object sender, EventArgs e) {
Console.WriteLi ne("baseClass_E ventB");
}
static void inheritedClass_ EventA(object sender, EventArgs e)
{
Console.WriteLi ne("inheritedCl ass_EventA");
}
static void inheritedBaseCl ass_EventA(obje ct sender, EventArgs
e) {
Console.WriteLi ne("inheritedBa seClass_EventA" );
}
static void baseClass_Event A(object sender, EventArgs e) {
Console.WriteLi ne("baseClass_E ventA");
}
}

class BaseClass
{
public void Foo() { // do something that triggers A
OnEventA();
}
public event EventHandler EventA, EventB, EventC;
private void OnEvent(EventHa ndler handler) {
if (handler != null) handler(this, EventArgs.Empty );
}
protected virtual void OnEventA() { OnEvent(EventA) ; }
protected virtual void OnEventB() { OnEvent(EventB) ; }
protected virtual void OnEventC() { OnEvent(EventC) ; }
}

class InheritedClass : BaseClass
{
protected override void OnEventA() {
base.OnEventA() ;
OnEventB();
OnEventC();
}
}
}
Mar 16 '07 #3
Oops; my sample was backward; the OP would have subscribes to "A" also
get messages when "B" or "C" are fired (and oddly not A); of course
via polymoprhism this would be (including A as a minor change):

class InheritedClass : BaseClass
{
protected override void OnEventB() {
base.OnEventB() ;
OnEventA();
}
protected override void OnEventC() {
base.OnEventC() ;
OnEventA();
}
}

Marc
Mar 16 '07 #4
On 16 Mrz., 13:01, "Marc Gravell" <marc.grav...@g mail.comwrote:
Oops; my sample was backward; the OP would have subscribes to "A" also
get messages when "B" or "C" are fired (and oddly not A);
The sample was of course shortened. I was just astounded that a
virtual event differs if you use add/remove or not.

Mar 16 '07 #5
Lots of things change with add / remove versus the default
implementation. .. and it does make sense... from the compiler's point
of view it is reasonable to assume that (private to the class) you are
referring to the field, otherwise you would never be able to *invoke*
the event - just [un]subscribe. But I can't see any reason why (in the
*developer's* code += and -= can't be routed via the event rather than
the field (since the compiler-provided implementation would do this
anyway...) with all other access (get, set, invoke) via the field -
but then you have to start remembering special cases, which is a PITA.

Perhaps a more desirable compiler feature would be to not let you
write virtual events without providing your own backing field (or
leaving it abstract) ;-p

Marc
Mar 16 '07 #6
I'm a bit stumbled.

The standard says:
"
1 The accessors of an inherited virtual event can be overridden in a derived
class by including an event declaration that specifies an override modifier.
2 This is known as an overriding event declaration.
3 An overriding event declaration does not declare a new event.
4 Instead, it simply specializes the implementations of the accessors of an
existing virtual event.
"

It says that the *accessors* of an inherited virtual event can be overriden
(1), but does not state you have to "declare" the accessors too (as with
EventC) to be able to override the accessors or if I can declare just the
event as virtual (as EventB).

It seems that from the compilers point of view, the EventB is virtual, but
just a field (special one), so it generates a private field, *but* it
generates virtual Add/Remove_EventB methods too, but it does not use them
when generating rest of the code even when an inherited class overrides
them. Maybe because it does not bind automatically generated code and
manually written code?

Another thing that I don't understand is that if I change the example to
this:

class InheritedClass : BaseClass
{
public override event EventHandler EventB;
..
..
..

The compiler generates a private copy of the overridden event, IMO,
violating the rule 3:

"3 An overriding event declaration does not declare a new event. "

"Karsten Schramm" <Ne************ **********@yaji robi.deha scritto nel
messaggio news:11******** **************@ e1g2000hsg.goog legroups.com...
Hi,

when I run the following code:

using System;

namespace ConsoleApplicat ion22
{
class Program
{
static void Main(string[] args)
{
BaseClass baseClass = new BaseClass();
BaseClass inheritedBaseCl ass = new InheritedClass( );
InheritedClass inheritedClass = new InheritedClass( );
baseClass.Event A += new EventHandler(ba seClass_EventA) ;
inheritedBaseCl ass.EventA += new
EventHandler(in heritedBaseClas s_EventA);
inheritedClass. EventA += new
EventHandler(in heritedClass_Ev entA);
Console.ReadLin e();
}

static void inheritedClass_ EventA(object sender, EventArgs e)
{
throw new Exception("The method or operation is not
implemented.");
}

static void inheritedBaseCl ass_EventA(obje ct sender, EventArgs
e)
{
throw new Exception("The method or operation is not
implemented.");
}

static void baseClass_Event A(object sender, EventArgs e)
{
throw new Exception("The method or operation is not
implemented.");
}
}

class BaseClass
{
public virtual event EventHandler EventA
{
add
{
this.EventB += this.BaseClass_ EventB;
this.EventC += this.BaseClass_ EventC;
}

remove
{
this.EventC -= this.BaseClass_ EventC;
this.EventB -= this.BaseClass_ EventB;
}
}

public virtual event EventHandler EventB;

public virtual event EventHandler EventC
{
add
{
}
remove
{
}
}

void BaseClass_Event C(object sender, EventArgs e)
{
throw new Exception("The method or operation is not
implemented.");
}

void BaseClass_Event B(object sender, EventArgs e)
{
throw new Exception("The method or operation is not
implemented.");
}
}

class InheritedClass : BaseClass
{
public override event EventHandler EventB
{
add
{
Console.WriteLi ne("EventB: Override add called");
}

remove
{
Console.WriteLi ne("EventB: Override remove called");
}
}

public override event EventHandler EventC
{
add
{
Console.WriteLi ne("EventC: Override add called");
}
remove
{
Console.WriteLi ne("EventC: Override remove called");
}
}
}
}
Then only the override of EventC will be called, not the one from
EventB. Was this to be expected?

Thx Karsten

Mar 16 '07 #7
public override event EventHandler EventB;
The compiler generates a private copy of the overridden event, IMO,
violating the rule 3:
I don't think it does... Reflector shows that such an override
declares a private field (as you expect if you don't provide an
implementation) , and that it *does not* call the base implementation.
It does *not* (however) declare a new event - merely an override to
the add_Blah and remove_Blah methods. In this hybrid the only way you
could make it work is to make an OnBlah that is overridden to call the
local field... but why mess with this anyways?

I guess you could provide your own implementation calling the base and
providing your own field. In a lot of scenarios you would want to use
an EventHandlerLis t anyway, so the benefit of the compiler-provided
event implementation is further reduced.

Marc
Mar 16 '07 #8
retraction: looking at the IL, maybe it does declare a new event at
the class, maybe not. I'm no longer 100% sure! But either way, it/they
hook into the same virtual/overload methods, so the result is the same
(ish).

Marc
Mar 16 '07 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

51
7001
by: Noam Raphael | last post by:
Hello, I thought about a new Python feature. Please tell me what you think about it. Say you want to write a base class with some unimplemented methods, that subclasses must implement (or maybe even just declare an interface, with no methods implemented). Right now, you don't really have a way to do it. You can leave the methods with a "pass", or raise a NotImplementedError, but even in the best solution that I know of,
11
1998
by: Dave Rudolf | last post by:
Hi all, Suppose that I have a class (let's call the class A) with a virtual method. I then define a subclass (B), which could potentially be extended by some other subclass (say, C). So, A <- B <- C. I want to prevent C from redefining the virtual method in same manner as how a "final" method in Java cannot be overridden.. Is there some way to do this in C++? Dave.
32
4525
by: Adrian Herscu | last post by:
Hi all, In which circumstances it is appropriate to declare methods as non-virtual? Thanx, Adrian.
14
12146
by: JPRoot | last post by:
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 MyNamespac public delegate void MyDel() public class MyBase public virtual...
175
8884
by: Ken Brady | last post by:
I'm on a team building some class libraries to be used by many other projects. Some members of our team insist that "All public methods should be virtual" just in case "anything needs to be changed". This is very much against my instincts. Can anyone offer some solid design guidelines for me? Thanks in advance....
5
5332
by: Action | last post by:
does it works like ordinary virtual method?? coz I find that child class can't invoke the event of the parent class. class parent { public virtual event SomeDelegate SomeChanged; } class child : parent {
1
1399
by: wendy | last post by:
I have got a problem while using the modal dialogs. In my code I need to open a modal dialog from the parent page and I need to enter some values in the dialog and save it. It takes the values properly and also does the validation of the values but it doesn't hit the event handler of the button where it is supposed to save those values and close the box. Any help is appreciated. Thanks
19
4757
by: Daniela Roman | last post by:
Hello, I try to fire an event under a button click event and maybe anybody can give a clue please. I have let's say a WEB grid with PageIndexChanged event: private void DataGrid1_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
7
2908
by: Christopher Pisz | last post by:
My problem is my derived class is getting called twice instead of the base and then the derived. I thought this was the purpose for virtuals and dynamic casting :/ I want my base class to have its method called and then the derived class have its method called. What am I not understanding? Int the following code, my Event Tester class is getting called twice for keyboard events when I step through the debugger:...
0
9487
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10069
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
9884
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
1
7285
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6556
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5168
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5324
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
3
3395
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2697
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.