Suppose I have the following Interface:
interface IBook
{
event EventHandler<EventArgs> PageChanged;
}
which I could implement without difficulty for this class:
class Novel : IBook
{
public event EventHandler<EventArgs> PageChanged;
protected void OnPageChanged()
{
EventHandler<EventArgs> pageChanged = PageChanged;
if (pageChanged != null) pageChanged(this, EventArgs.Empty);
}
}
however, if I now have an object called Encyclopedia
defined as:
class Encyclopedia : IBook
{
public class EncyclopediaEventArgs : EventArgs
{
public int Volume
{
get { return volume; }
}
private int volume;
public EncyclopediaEventArgs(int volume)
{
this.volume = volume;
}
}
public event EventHandler<EncyclopediaEventArgs> PageChanged;
protected void OnPageChanged(int volume)
{
EventHandler<EncyclopediaEventArgs> pageChanged = PageChanged;
if (pageChanged != null) pageChanged(this, new EncyclopediaEventArgs(volume));
}
}
which has all the workings of a Book
, but with the added event argument field of Volume
. When I compile, I get an error (as surmised I would):
error CS0738: 'Encyclopedia' does not implement interface member 'IBook.PageChanged'. 'Encyclopedia.PageChanged' cannot implement 'IBook.PageChanged' because it does not have the matching return type of 'System.EventHandler'
It states that it cannot implement IBook.PageChanged
because System.EventHandler<System.EventArgs>
is not the return type, even though EncyclopediaEventArgs
derives from System.EventArgs
.
My question, therefore, is, would it be possible to derive such a class as Encyclopedia
which adds the additional Volume
field to its event arguments?
(Any discussion is very much welcome as to why this is or is not a poor design/architecture decision!)
It seems fairly straight forward to do this:
interface IBook<T> where T : EventArgs
{
event EventHandler<T> PageChanged;
}
class Novel : IBook<EventArgs> { ... }
class Encyclopedia : IBook<Encyclopedia.EncyclopediaEventArgs> { ... }
If you still need a plain IBook
then you would do this:
interface IBook { }
interface IBook<T> : IBook where T : EventArgs
{
event EventHandler<T> PageChanged;
}
It depends a bit on how you are going to use IBook
. You could create a generic parameter for the EventArgs
like so:
public interface IBook<TEventArgs> where TEventArgs : EventArgs
{
event EventHandler<TEventArgs> PageChanged;
}
public class Novel : IBook<EventArgs>
{
event EventHandler<EventArgs> PageChanged;
}
public class Encyclopedia : IBook<EncyclopediaEventArgs>
{
event EventHandler<EncyclopediaEventArgs> PageChanged;
}
But then you can't use IBook
without the generic type if you need PageChanged
for other purposes.
Another way is to just keep the event EventHandler<EventArgs> PageChanged;
have the Encyclopedia implementation pass a EncyclopediaEventArgs
and just cast in the event handler.
class Encyclopedia : IBook
{
public class EncyclopediaEventArgs : EventArgs
{
}
public event EventHandler<EventArgs> PageChanged;
protected void OnPageChanged(int volume)
{
EventHandler<EventArgs> pageChanged = PageChanged;
if (pageChanged != null) pageChanged(this, new EncyclopediaEventArgs(...));
}
}
public class BookReader
{
public void OnPageChanged(object sender, EventArgs e)
{
if (sender is Encyclopedia && e is EncyclopediaEventArgs)
{
EncyclopediaEventArgs ee = (EncyclopediaEventArgs)e;
}
else
{
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.