Can a Derived Class Subscribe to Base Class' Events?

J

Jerry Nixon

I hope this is easy,

First, I simply must not override MyMethod as shown in the sample code
- that is an unbreakable requirement. The purpose of the event is to
allow me to extend MyMethod inside the derived class, within MyMethod's
transaction and without overloading it.

The event subscription in the base is because I get a null exception
without it; I don't want to subscribe to it in the base. The event
handler in the base is because I cannot subscribe to it in the base
without the handler present.

Thank you in advance, Jerry

Code:
class abstract MyBase
{
public delegate void MyDelegate(System.EventArgs args);
public static event MyDelegate MyEvent;
static MyBase()
{
MyEvent += MyBaseHander;
}
static void MyMethod()
{
// transaction.begin
MyEvent(new System.EventArgs());
// transaction.commit
}
static void MyBaseHander(System.EventArgs args)
{
// This executes just fine
}
}
class MyDerived : MyBase
{
static MyDerived()
{
MyEvent += MyDerivedHandler;
}
static void MyDerivedHandler(System.EventArgs args)
{
// This does not execute!?
}
}
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

Why everything is static?

beside the code will never compile , these lines are WRONG:

class abstract MyBase == >> abstract class MyBase

MyEvent += MyBaseHander; == > MyEvent += new MyDelegate( MyBaseHander );

the same with myderived


Are you sure the constructor of MyDerived is called?
Most probably that is where the problem is.

still no idea why the static"ness"


cheers,
 
J

Jerry Nixon

Ignacio,

I should have stated this initially. It is required that MyMethod() be
static. As a result many other things become static - that's the reason
for the static"ness".

And you are right, the static constructor in the derived class is not
being called. I am at a loss.

Thanks again, I hope you can help me, Jerry

I wrote the sample code in notepad (thus the errs), I have loaded it in
Visual Studio to make the corrections (exactly what you suggested in
fact). Here's a more accurate sample (sorry for the errs, but it was
just a sample to get the point):

Code:
abstract class MyBase
{
public delegate void MyDelegate(System.EventArgs args);
public static event MyDelegate MyEvent;
static MyBase()
{
MyEvent += new MyBaseHander();
}
static void MyMethod()
{
// transaction.begin
MyEvent(new System.EventArgs());
// transaction.commit
}
static void MyBaseHander(System.EventArgs args)
{
// This executes just fine
}
}
class MyDerived : MyBase
{
static MyDerived()
{
MyEvent += new MyDerivedHandler();
}
static void MyDerivedHandler(System.EventArgs args)
{
// This does not execute!?
}
}
 
B

Bruce Wood

First of all, as Ignacio pointed out, your event subscription code is
incorrect. You cannot say:

MyEvent += new MyDerivedHandler();

you must, instead, say:

MyEvent += new MyDelegate(MyDerivedHandler);

Second, there is no need for MyBaseHandler. The problem is that you are
using the wrong idiom for invoking the event delegate. Your code in the
base class should read:

static void MyMethod()
{
// transaction.begin
if (MyEvent != null)
{
MyEvent(System.EventArgs.Empty);
}
// transaction.end
}

this is the standard C# event invocation idiom.

You say that "it is required that MyMethod be static". Why is that? Is
it really true that it has to be static, or could it be contained in a
singleton object? The latter would improve your situation a lot, and
open up possibilities for other, more elegant solutions involving
inheritance.

Could you use a singleton class here instead of a static method?
 
J

Jerry Nixon

SOLVED

In reality, I did not solve it, I just realized the issue. The problem
is that a class' static constructor is not called until a member of the
class is called (this seems very logical). I can't see why the
following is true, but calling a base class' member is not sufficient
to invoke the derived class constructor! Seems nuts, I know.

A proxy method is my solution (see below) did it. Because I am working
with VS2005RC I think my += syntax is different than what you guys are
suggesting - otherwise thanks for the help. I hope this solution helps
someone.

I have tested and debugged the sample code. It works.

Code:
public abstract class MyBase
{
public delegate void MyDelegate(System.EventArgs args);
public static event MyDelegate MyEvent;
internal static void Base_MyMethod()
{
// transaction.begin
if (MyEvent != null)
{
MyEvent(new System.EventArgs());
}
// transaction.commit
}
}
public class MyDerived : MyBase
{
static MyDerived()
{
MyEvent += MyDerivedHandler;
}
static void MyDerivedHandler(System.EventArgs args)
{
throw new System.ApplicationException("It works!");
}
public static void MyMethod()
{
Base_MyMethod();
}
}

Here's my unit test

Code:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace UnitTests
{
[TestClass()]
public class MyDerivedTest
{
private TestContext testContextInstance;
public TestContext TestContext
{
get{return testContextInstance;}
set{testContextInstance = value;}
}
[DeploymentItem("Library.dll")]
[TestMethod()]
[ExpectedException(typeof(System.ApplicationException))]
public void MyTest()
{
MyDerived.MyMethod();
}

}
}
 
J

Jon Skeet [C# MVP]

Jerry Nixon said:
I should have stated this initially. It is required that MyMethod() be
static. As a result many other things become static - that's the reason
for the static"ness".

That gets rid of polymorphism, unfortunately, which is where your
problem lies. You will have to either use instances, or make sure that
the static constructor of the derived class is called - which involves
accessing something which is genuinely only in the derived class.
 
J

Jon Skeet [C# MVP]

Jerry Nixon said:
In reality, I did not solve it, I just realized the issue. The problem
is that a class' static constructor is not called until a member of the
class is called (this seems very logical). I can't see why the
following is true, but calling a base class' member is not sufficient
to invoke the derived class constructor! Seems nuts, I know.

It doesn't seem particularly nuts to me. Would you want the CLR to look
at all the referenced assemblies, including those it hadn't already
loaded, just to make sure it finds all the derived classes? Nope -
better to only do things when you need to, in general.
A proxy method is my solution (see below) did it. Because I am working
with VS2005RC I think my += syntax is different than what you guys are
suggesting - otherwise thanks for the help. I hope this solution helps
someone.

Yes, C# 2.0 has inferred delegate types, which makes things rather
simpler.
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,


Jerry Nixon said:
SOLVED

In reality, I did not solve it, I just realized the issue. The problem
is that a class' static constructor is not called until a member of the
class is called (this seems very logical). I can't see why the
following is true, but calling a base class' member is not sufficient
to invoke the derived class constructor! Seems nuts, I know.

Not at all, it's logic, why you would want to initialize the type if nobody
is using it?

Beside, you have it the opposite, if a base class is used the derived
classes do not intervine at all therefore they do not get initialized, now
the opposite is different (and what you want), if you create a derived class
then the base is used ( as it is part of the derived) and the static
constructor should be called. hence if you instead of initialize the base,
do the same with the derived you will get the result you want.


The reason the static constructors are not called is efficiency , if the
runtime when a new program loads the runtime would have to scan all the
types in all the assemblies and execute the static constructors, not very
smart, neither very efficient.



cheers,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top