【问题标题】:Using Events in Interfaces在接口中使用事件
【发布时间】:2014-10-01 05:44:01
【问题描述】:

我正在实现一个使用复合设计模式的菜单系统。我有以下 MenuElement 界面:

public interface MenuElement
{
    void AddMenuElement( MenuElement menuToAdd );
    void RemoveMenuElement( MenuElement menuToRemove );
    MenuElement GetMenuElement( int index );
    void Activate();
}

我正在考虑在这个接口中包含一个“OnActivate”事件,以便实现这个接口的 MenuItem 在激活时可以触发功能。我尝试这样实现它:

public interface MenuElement
{
    public delegate void MenuEvent();
    event MenuEvent onActivate;

    void AddMenuElement( MenuElement menuToAdd );
    void RemoveMenuElement( MenuElement menuToRemove );
    MenuElement GetMenuElement( int index );
    void Activate();
}

但是,编译器不允许我在接口内声明委托。我知道一个名为 EventHandler 的 C# 事件类型,但与我想要的 MenuEvent 不同,它需要 object 和 EventArgs 参数。我也考虑过移动我的事件并委托给 MenuItem,但我仍然很好奇是否可以让界面包含自定义事件。

这可能吗?还是在这种情况下我必须使用 C# 的 EventHandler 类?

【问题讨论】:

  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • 1.没有理由在接口中声明委托类型。 2. 为什么你想要标准的EventHandler 签名?它的存在是有充分理由的,然后你只有public event EventHandler<MyEventArgs> Activated;
  • 之所以不想使用EventHandler,是因为想着用不带任何参数的函数来处理事件。在处理无参数事件处理函数的情况下,您会怎么做?

标签: c# events interface delegates


【解决方案1】:

为什么不使用EventHandler?例如

  // I've added "I" since it's an Interface
  public interface IMenuElement {
    void AddMenuElement(MenuElement menuToAdd);
    void RemoveMenuElement(MenuElement menuToRemove);
    void Activate();

    // I've changed your 
    // MenuElement GetMenuElement(int index)
    // to indexer
    MenuElement this[int index] {get;}

    // Event of interest; I've renamed it from onActivate
    event EventHandler Activated;
  }

  ...
  // Possible interface implementation
  public class MyMenuElement: IMenuElement {
    ...
    // name like "onActivate" is better to use here, as a private context
    private void onActivated() {
      if (Object.ReferenceEquals(null, Activated)) 
        return;

      Activated(this, EventArgs.Empty);
    }

    public void Activate() {
      // Some staff here
      ... 
      // Raising the event
      onActivated();
    }
  }

【讨论】:

  • 我不清楚 EventArgs 应该如何与无参数事件处理函数一起使用。这个答案解释了很多,谢谢。
【解决方案2】:

接口并不意味着实现字段;它用于定义合同(签名),仅此而已。

如果你想提供一个基字段,结合一个“接口”,考虑一个抽象类。抽象类对于提供部分实现很有用。

public abstract class MenuElement
{
    public delegate void MenuEvent();
    event MenuEvent onActivate;

    abstract virtual void AddMenuElement( MenuElement menuToAdd );
    abstract virtual void Activate();
}

如果还有一个接口也很重要,那么只需让您的 MenuElement 类继承该接口,并将其传递给它的后代。抽象类可以在不实现接口的情况下继承接口,以便将它们传递给叶类,保持便利因素。

请记住,您也可以在接口中声明属性,但叶类仍然必须实现该属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多