Question

I have a base class DockedToolWindow : Form, and many classes that derive from DockedToolWindow. I have a container class that holds and assigns events to DockedToolWindow objects, however I want to invoke the events from the child class.

I actually have a question about how to implement what this MSDN site is telling me to do. This section below is giving me the problem:

    // The event. Note that by using the generic EventHandler<T> event type
    // we do not need to declare a separate delegate type.
    public event EventHandler<ShapeEventArgs> ShapeChanged;

    public abstract void Draw();

    //The event-invoking method that derived classes can override.
    protected virtual void OnShapeChanged(ShapeEventArgs e)
    {
        // Make a temporary copy of the event to avoid possibility of
        // a race condition if the last subscriber unsubscribes
        // immediately after the null check and before the event is raised.
        EventHandler<ShapeEventArgs> handler = ShapeChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

Sure this example compiles and works, but when I replace "ShapeChanged" with "Move" (an event I acquired from deriving from Form), it errors saying I cannot have Move on the right side without += or -=. I also removed the ShapeEventArgs generic tags.

Any incite on why this isn't working? What's the difference between an event declared within the class and one that is inherited?

Was it helpful?

Solution

You cannot directly fire base class events. This is exactly the reason why you had to make your OnShapeChanged method protected instead of private.

Use base.OnMove() instead.

OTHER TIPS

From the C# language spec, section 10.7 (emphasis added):

Within the program text of the class or struct that contains the declaration of an event, certain events can be used like fields. To be used in this way, an event must not be abstract or extern, and must not explicitly include event-accessor-declarations. Such an event can be used in any context that permits a field. The field contains a delegate (§15) which refers to the list of event handlers that have been added to the event. If no event handlers have been added, the field contains null.

Thus, the reason you can't treat the Move event like a field is that it is defined in a different type (in this case, your superclass). I agree with @womp's speculation that the designers made this choice to prevent unintended monkeying with the event. It seems obviously bad to allow unrelated types (types not derived from the type declaring the event) to do this, but even for derived types, it might not be desirable. They probably would have had to include syntax to allow the event declaration to be made private or protected with respect to field-style usage, so my guess is that they opted to just disallow it entirely.

The difference is scope. Inside your class, you can control how your event delegates are handled, however, your class cannot control what the base class is doing. It might be doing some crazy behind-the-scenes stuff with the event and its handlers. If you simply "reassigned" the Move event, you would be wiping out the multicast delegate list for the event.

I'm guessing they put a compiler restriction on this because its a very unsafe practice, and would essentially give any descendant class the ability to destroy the event model of its parent.

You only need the code you posted in the class where the event itself is defined. All derived classes should simply call OnShapeChanged() or OnMove() directly, without the copying etc., so you shouldn't be writing that code at all in your classes (since the Move event is defined in the base).

If you do need to do some kind of processing in the derived class (maybe you need to fiddle with your collection class?), you override the virtual OnXXX call and do you stuff before calling base.OnXXX(). In the MSDN article, the Circle class corresponds to your DockedToolWindow class. The same pattern should be available to your derived classes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top