8

Why can't I use the event declared in Base from Sub?

class Program
{
    static void Main(string[] args)
    {
        Sub sub = new Sub();
        sub.log += new Base.logEvent(sub_log);
        sub.go();
    }

    static void sub_log(string message, int level)
    {
        Console.Out.WriteLine(message + " " + level);
    }
}

public abstract class Base
{
    public delegate void logEvent(String message, int level);

    public event logEvent log;
}

public class Sub : Base
{

    public void go()
    {
        log("Test", 1); // <-- this won't compile
    }
}
Pang
  • 9,564
  • 146
  • 81
  • 122
klundby
  • 301
  • 1
  • 3
  • 17

3 Answers3

9

Events may only be invoked from the class that declares them.

From outside of the definition of a class (even in a derived class) you can only register and unregister from an event. Inside of the class, the compiler only allows you to raise the event. This is a by-design behavior of C# (which actually changes slightly in C#4 - Chris Burrows describes the changes on his blog).

What you want to do here is provide a RaiseLogEvent() method in the base class, which would allow the derived class to invoke this event.

public abstract class Base
{ 
  public delegate void logEvent(String message, int level); 

  public event logEvent log; 

  protected void RaiseLogEvent( string msg, int level )
  {
      // note the idomatic use of the copy/test/invoke pattern...
      logEvent evt = log;
      if( evt != null )
      {
          evt( msg, level );
      }
  }
} 

As an aside, you should consider using the EventHandler<> delegate type, rather than creating your own event types when possible.

LBushkin
  • 129,300
  • 32
  • 216
  • 265
  • So instead of declareing a delegate i make a subclass of EventArgs that holds my message and loglevel? Why is that better? – klundby Jun 17 '10 at 19:40
  • @klundy: The standard pattern for event handler in .NET is to supply a sender and a object representing the arguments. This allows subscribers of envents to retain consistency in their signatures, and reduces confusion about what parameters are expected. With C# 4's delegate co/contra-variance it becomes easier to write generic event handlers when the handler does not care about the arguments or sender. What I've done in many cases is to create a `EventArgs` generic class that inherits from `EventArgs` and allows me to pass data to handlers ... but that's just a style choice. – LBushkin Jun 17 '10 at 20:32
  • 1
    This is one of the most useless, braindamaged, clueless bits of language design I've seen in a long time. – Glenn Maynard Jan 21 '14 at 16:33
2

Because events can only be called from the declaring class. Just create a method in the base class to call it:

protected virtual RaiseLogEvent(string s, int i)
{
  log(s, i);
}

So you can use it in deriving classes, and even override it.

On another note, I would strongly advise you to follow the design guidelines for events, and create an own EventArgs class, and use the EventHandler<T> delegate.

Femaref
  • 60,705
  • 7
  • 138
  • 176
0

Yes, you can declare events in a base class so that they can also be raised from derived classes.

Create a protected invoking method for the event. By calling this invoking method, derived classes can invoke the event.

Read the standard way to do so here:
How to raise base class events in derived classes

Pang
  • 9,564
  • 146
  • 81
  • 122
Gul Ershad
  • 1,743
  • 2
  • 25
  • 32