473,402 Members | 2,064 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,402 software developers and data experts.

Virtual Event doesn't behave as expected.

Hi,

when I run the following code:

using System;

namespace ConsoleApplication22
{
class Program
{
static void Main(string[] args)
{
BaseClass baseClass = new BaseClass();
BaseClass inheritedBaseClass = new InheritedClass();
InheritedClass inheritedClass = new InheritedClass();
baseClass.EventA += new EventHandler(baseClass_EventA);
inheritedBaseClass.EventA += new
EventHandler(inheritedBaseClass_EventA);
inheritedClass.EventA += new
EventHandler(inheritedClass_EventA);
Console.ReadLine();
}

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

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

static void baseClass_EventA(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_EventC(object sender, EventArgs e)
{
throw new Exception("The method or operation is not
implemented.");
}

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

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

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

public override event EventHandler EventC
{
add
{
Console.WriteLine("EventC: Override add called");
}
remove
{
Console.WriteLine("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 1595
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 ConsoleApplication22
{
class Program
{
static void Main(string[] args)
{
BaseClass baseClass = new BaseClass();
BaseClass inheritedBaseClass = new InheritedClass();
InheritedClass inheritedClass = new InheritedClass();

baseClass.EventA += new EventHandler(baseClass_EventA);
baseClass.EventB += new EventHandler(baseClass_EventB);
inheritedBaseClass.EventA += new
EventHandler(inheritedBaseClass_EventA);
inheritedBaseClass.EventB += new
EventHandler(inheritedBaseClass_EventB);
inheritedClass.EventA += new
EventHandler(inheritedClass_EventA);
inheritedClass.EventB += new
EventHandler(inheritedClass_EventB);

baseClass.Foo();
inheritedBaseClass.Foo();
inheritedClass.Foo();

Console.ReadLine();
}
static void inheritedClass_EventB(object sender, EventArgs e)
{
Console.WriteLine("inheritedClass_EventB");
}
static void inheritedBaseClass_EventB(object sender, EventArgs
e) {
Console.WriteLine("inheritedBaseClass_EventB");
}
static void baseClass_EventB(object sender, EventArgs e) {
Console.WriteLine("baseClass_EventB");
}
static void inheritedClass_EventA(object sender, EventArgs e)
{
Console.WriteLine("inheritedClass_EventA");
}
static void inheritedBaseClass_EventA(object sender, EventArgs
e) {
Console.WriteLine("inheritedBaseClass_EventA");
}
static void baseClass_EventA(object sender, EventArgs e) {
Console.WriteLine("baseClass_EventA");
}
}

class BaseClass
{
public void Foo() { // do something that triggers A
OnEventA();
}
public event EventHandler EventA, EventB, EventC;
private void OnEvent(EventHandler 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...@gmail.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**********************@yajirobi.deha scritto nel
messaggio news:11**********************@e1g2000hsg.googlegro ups.com...
Hi,

when I run the following code:

using System;

namespace ConsoleApplication22
{
class Program
{
static void Main(string[] args)
{
BaseClass baseClass = new BaseClass();
BaseClass inheritedBaseClass = new InheritedClass();
InheritedClass inheritedClass = new InheritedClass();
baseClass.EventA += new EventHandler(baseClass_EventA);
inheritedBaseClass.EventA += new
EventHandler(inheritedBaseClass_EventA);
inheritedClass.EventA += new
EventHandler(inheritedClass_EventA);
Console.ReadLine();
}

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

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

static void baseClass_EventA(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_EventC(object sender, EventArgs e)
{
throw new Exception("The method or operation is not
implemented.");
}

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

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

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

public override event EventHandler EventC
{
add
{
Console.WriteLine("EventC: Override add called");
}
remove
{
Console.WriteLine("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 EventHandlerList 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
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...
11
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...
32
by: Adrian Herscu | last post by:
Hi all, In which circumstances it is appropriate to declare methods as non-virtual? Thanx, Adrian.
14
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...
175
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...
5
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...
1
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...
19
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...
7
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...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
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,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
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,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
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...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
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...

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.