Replacing an event

  • Thread starter Thread starter MikeP
  • Start date Start date
M

MikeP

Hi there,

I wrote a replacement for the native .NET class "FileDialog" with my own
"FileOk" event (triggered when the user selects a file and clicks OK). Let's
say I now want to create a derivative called "MyFileDialog" and replace the
"FileOk" event with a new event called "MyFileOk". Users of this class
should therefore rely on the latter event and not "FileOk" from the base
class. Is it therefore possible to hide the base class' "FileOk" event so
that users can't invoke it. Redefining it as private doesn't help (the base
class version kicks in instead) so the only way I can see is to redefine it
as "public" (using the "new" keyword) and then throwing a
"System.NotImplementedException" (also asserting in the debug version). This
is ugly IMO however so I'm hoping there's a cleaner way. Any advice would be
appreciated. Thanks.
 
I wrote a replacement for the native .NET class "FileDialog" with my own
"FileOk" event (triggered when the user selects a file and clicks OK). Let's
say I now want to create a derivative called "MyFileDialog" and replace the
"FileOk" event with a new event called "MyFileOk". Users of this class
should therefore rely on the latter event and not "FileOk" from the base
class. Is it therefore possible to hide the base class' "FileOk" event so
that users can't invoke it. Redefining it as private doesn't help (the base
class version kicks in instead) so the only way I can see is to redefine it
as "public" (using the "new" keyword) and then throwing a
"System.NotImplementedException" (also asserting in the debug version). This
is ugly IMO however so I'm hoping there's a cleaner way. Any advice would be
appreciated. Thanks.

If you don't want a client to be able to use a member of the base
class, you shouldn't derive from it.

You could make it virtual, override it, and add a deprecated attribute
to it - but it's a bit horrible. You *should* be able to use an
instance of a derived class as if it were an instance of the base
class.

Jon
 
If you don't want a client to be able to use a member of the base
class, you shouldn't derive from it.

You could make it virtual, override it, and add a deprecated attribute
to it - but it's a bit horrible. You *should* be able to use an
instance of a derived class as if it were an instance of the base
class.

Thanks for the feedback. Actually I agree with this in principle. However,
this was a very late change so I didn't want to have to start aggregating
the base class as a private member (as one possible solution), especially
for this one minor change. Note that in C++ you have more flexibility with
this issue. You can privately derive from a base class for instance and then
publicly expose only what you want. I find this approach somewhat ugly as
well however. In any case, I'll probably stick with my original idea until
the next release since I control all clients anyway (though I might add the
obsolete attribute you suggested). Anyway, thanks again.
 
You could make it virtual, override it, and add a deprecated attribute
to it - but it's a bit horrible. You *should* be able to use an
instance of a derived class as if it were an instance of the base
class.

I *expect* to be able to use a derived class as if it were an instance
of the base class. :)

I have a feeling that the derived class event wants to pass more
information to the client than the base event. What I personally
would do is fire both events in the derived class. Let the client
decide which event to hook to, or even both (just document that both
events would be fired). I don't like this but it would be the
"easiest" solution...

Or you could virutalize the event, an OnEvent() method, and derive the
event args for the derived event from the base eventargs. Then the
client can hook to the same name (regardless). The derived class
fires the event with the derived event args, and the base class fires
the event with the base event args. It would be up to the client to
attempt to cast the base event args structure in the event handler to
determine what fired. I don't really like that either, it requires
the client to jump through some hoops in the event handler code....

The second case could look something like (IMO NOT "a good idea
(tm)"):
public class BaseEventArgs : EventArgs
{
public string BaseInfo
{
get
{
return "Only Base Info available";
}
}
}

public class DerivedEventArgs : BaseEventArgs
{
public string DerivedInfo
{
get
{
return "DerivedInfoAvailable";
}
}
}

public class BaseClass
{
virtual public event EventHandler<BaseEventArgs> MyEvent;

protected virtual void OnMyEvent()
{
EventHandler<BaseEventArgs> b = MyEvent;
if (b != null)
b(this, new BaseEventArgs());
}

internal void Fire()
{
OnMyEvent();
}
}

public class DerivedClass : BaseClass
{
public override event EventHandler<BaseEventArgs> MyEvent;

protected override void OnMyEvent()
{
EventHandler<BaseEventArgs> b = MyEvent;
if (b != null)
b(this, new DerivedEventArgs());
}
}

class Program
{
static void Main(string[] args)
{
BaseClass s = new DerivedClass();
s.MyEvent += new EventHandler<BaseEventArgs>(s_MyEvent);

Console.WriteLine("Firing Derived Class instance");
s.Fire();

s = new BaseClass();
s.MyEvent += new EventHandler<BaseEventArgs>(s_MyEvent);
Console.WriteLine("Firing Base Class instance");
s.Fire();
}


static void s_MyEvent(object sender, BaseEventArgs e)
{
DerivedEventArgs de = e as DerivedEventArgs;
if (de != null)
{
// Do stuff with derived event args
Console.WriteLine(de.DerivedInfo);
}
// Can do stuff with base event info
Console.WriteLine(e.BaseInfo);
}
}
 

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

Back
Top