4

When implementing events, one can provide code for add and remove a event handler. However, events can be accessed in three ways:

MyEvent += Handler;                // add accessor
MyEvent -= Handler;                // remove accessor
MyEvent(this, EventArgs.Empty);    // not supported by an accessor

Wouldn't it be obvious to have another accessor called invoke that is responsible for that? My thoughts are:

class BaseClass
{
  public virtual event EventHandler MyEvent { add; remove; protected invoke; }
}

class DerivedClass : BaseClass
{
  public override event EventHandler MyEvent
  {
    invoke
    {
      // new code before event
      base.MyEvent(this, ...);
      // new code after event
    }
  }
}

I know of the old-style pattern, which is to implement an OnMyEvent(...) method. But there two important drawback with this approach:

  1. Event code is scattered -> less organized code base
  2. You can't refactor the event easily (e.g., rename it)

Edit: Obviously the compiler team already designed for this feature (See GetRaiseMethod()).

Matthias
  • 15,919
  • 5
  • 39
  • 84

1 Answers1

5

This is on purpose, so that you don't invoke events that you don't "own".

Edit (to address you edit): even in an inherited class it is unclear whether you should always be able to invoke it. Usually yes, and therefore the common pattern is well set out:

  • Define an event (not prefixed with On)
  • Create a protected virtual method with the same name but prefixed with On, which accepts the appropriate EventArgs and just does the null check and the invocation.
  • Always raise the event through the virtual method

This pattern allows greater flexibility; one can change or omit events or do post-event processing by inheriting the method. If no method exist, the event invocation is private.

Lucero
  • 59,176
  • 9
  • 122
  • 152
  • 1
    If you could go and just do `button1.Click(...)` or so it would raise the event without it being triggered by the button itself. Only the Button class should be able to raise the event. That's why you can invoke it from within the class that defines it, but not otherwise. – Lucero Jul 31 '12 at 09:43
  • I knew that. Added some more explanation. Hope this helpes. – Matthias Jul 31 '12 at 09:48
  • Your syntax doesn't work - mixing methods and delegates makes it ambiguous (what does `base.MyEvent` refer to?). How shall parameters be passed along? How would reflection work on them? Who would be allowed to call the invoke? – Lucero Jul 31 '12 at 12:49
  • What's ambiguous? `base.MyEvent` refers to `BaseClass.MyEvent`. The semantics are clearly defined. Parameters are *maybe* a problem, because delegates can have multiple of them. Reflection could work just as always. As the `protected` modifier indicates, in this case the derived class can invoke the event. – Matthias Jul 31 '12 at 12:57
  • The ambiguity is that with your approach at some places it refers to a delegate and in others to a method. How would I check whether there are any subscribers or enumerate them from within the "invoke" method? `if (MyEvent != null)` wouldn't even be valid anynmore. – Lucero Jul 31 '12 at 15:29
  • Sorry, the post was not about to propose a fully-fledged syntax. But there will be no more innovations, if we just stick to the old stuff. Nevertheless, the question was, why the invocation is detached from the event itself. Thanks for your answer, but it doesn't help me a lot. – Matthias Aug 01 '12 at 12:15
  • I'm sorry that my answer wasn't helpful. The CLI designers initially seemed to have similar thoughts to yours, and they designed specific metadata for a "event raise" method (see the `EventInfo.GetRaiseMethod` method). However, this is not used at all by the mainstream languages and while C++/CLI allows them to be defined, I have never come across anything using them. There must have been good reasons not to implement this. You could maybe ask Eric Lippert (via the contact form on his blog) to answer this? See also: http://stackoverflow.com/questions/4523511 – Lucero Aug 01 '12 at 14:17
  • Okay, this link helps much more :) Thank you. I already discovered this method (see edit). But yea.. maybe Eric Lippert is the only one who can help here :) – Matthias Aug 01 '12 at 14:33