Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Events in Interfaces

I'm implementing a menu system that uses a composite design pattern. I have the following MenuElement interface:

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

I was thinking of including an "OnActivate" event in this interface so that MenuItems that implement this interface can trigger functions when activated. I tried implementing it like this:

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

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

However, the compiler won't let me declare a delegate inside an interface. I'm aware of a C# event type called EventHandler but unlike my desired MenuEvent, it requires both object and EventArgs parameters. I've also considered moving my event and delegate over to MenuItem instead, but I'm still curious if it is possible to have an interface include a custom event.

Is this possible? Or would I have to use C#'s EventHandler class in this situation?

like image 452
TheYokai Avatar asked Oct 01 '14 05:10

TheYokai


2 Answers

Why don't you use EventHandler? E.g.

  // 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();
    }
  }
like image 176
Dmitry Bychenko Avatar answered Oct 10 '22 22:10

Dmitry Bychenko


An interface is not meant to implement a field; it is there to define contracts (signatures), that is all.

If you want to provide a base field, combined with an "interface", consider an abstract class. abstract classes are useful for providing partial implementations.

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

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

If it is important to also have an interface then just have your MenuElement class inherit the interface, and pass it on to its descendants. Abstract classes can inherit interfaces without implementing them, in order to pass them along to the leaf classes, maintaining the convenience factor.

Keep in mind you can also declare a property in an interface, but leaf classes still have to implement the property.

like image 21
codenheim Avatar answered Oct 10 '22 20:10

codenheim