是否可以实现 C# 接口并扩展事件的参数

本文关键字:扩展 事件 参数 接口 实现 是否 | 更新日期: 2023-09-27 18:33:59

假设我有以下接口:

interface IBook
{
    event EventHandler<EventArgs> PageChanged;
}

我可以毫无困难地为这个类实现:

class Novel : IBook
{
    public event EventHandler<EventArgs> PageChanged;
    protected void OnPageChanged()
    {
        EventHandler<EventArgs> pageChanged = PageChanged;
        if (pageChanged != null) pageChanged(this, EventArgs.Empty);
    }
}

但是,如果我现在有一个名为 Encyclopedia 的对象定义为:

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));
    }
}

它具有Book的所有工作原理,但添加了 Volume 的事件参数字段。 当我编译时,我得到一个错误(正如推测的那样(:

错误 CS0738:"百科全书"未实现接口成员"IBook.PageChanged"。"Encyclopedia.PageChanged"无法实现"IBook.PageChanged",因为它没有匹配的返回类型"System.EventHandler">

指出它无法实现IBook.PageChanged,因为System.EventHandler<System.EventArgs>不是返回类型,即使EncyclopediaEventArgs派生自System.EventArgs

因此,我的问题是,是否有可能派生出这样一个类,例如Encyclopedia,将额外的Volume字段添加到其事件参数中?

(非常欢迎任何关于为什么这是一个糟糕的设计/架构决策的讨论!

是否可以实现 C# 接口并扩展事件的参数

这样做似乎相当简单:

interface IBook<T> where T : EventArgs
{
    event EventHandler<T> PageChanged;
}
class Novel : IBook<EventArgs> { ... }
class Encyclopedia : IBook<Encyclopedia.EncyclopediaEventArgs> { ... }

如果您仍然需要一个普通IBook那么您可以这样做:

interface IBook { }
interface IBook<T> : IBook where T : EventArgs
{
    event EventHandler<T> PageChanged;
}

这有点取决于您如何使用IBook .您可以为EventArgs创建一个泛型参数,如下所示:

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;
}

但是,如果需要PageChanged用于其他目的,则不能在没有泛型类型的情况下使用IBook

另一种方法是保持event EventHandler<EventArgs> PageChanged;让百科全书实现传递一个EncyclopediaEventArgs,然后只在事件处理程序中强制转换。

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
        {
        }
    }
}