Поднимите события базового класса в производных классах C#

StackOverflow https://stackoverflow.com/questions/780022

  •  13-09-2019
  •  | 
  •  

Вопрос

У меня есть базовый класс DockedToolWindow: форма и многие классы, которые вытекают из DockedToolWindow. У меня есть класс контейнеров, который удерживает и назначает события для объектов DockedToolWindow, однако я хочу вызвать события из детского класса.

У меня на самом деле есть вопрос о том, как реализовать то, что это Сайт MSDN говорит мне сделать. Этот раздел ниже дает мне проблему:

    // 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);
        }
    }

Конечно, этот пример компилизируется и работает, но когда я заменяю «ShapeChanged» на «Move» (событие, которое я приобрел из получения из формы), это ошибки говорят, что я не могу двигаться на правой стороне без += или -=. Я также удалил общие теги ShapeeVentargs.

Любой подстрекатель о том, почему это не работает? В чем разница между событием, объявленным в классе и унаследованным?

Это было полезно?

Решение

Вы не можете напрямую стрелять в события базового класса. Это именно то, почему вы должны были сделать свой OnShapeChanged метод protected вместо private.

Использовать base.onmove () вместо.

Другие советы

Из языковой спецификации C#, раздел 10.7 (выделение добавлено):

В тексте программы класса или структуры, который содержит объявление события, определенные события могут использоваться как поля. Анкет Чтобы использоваться таким образом, событие не должно быть абстрактным или внешним, и не должно явно включать в себя декларации событий-аксессор. Такое событие можно использовать в любом контексте, который разрешает поле. Поле содержит делегат (§15), который относится к списку обработчиков событий, которые были добавлены к событию. Если обработчики событий не были добавлены, поле содержит NULL.

Таким образом, причина, по которой вы не можете относиться к событию движения, как поле, заключается в том, что оно определено в другом типе (в данном случае, ваш суперкласс). Я согласен с предположениями @womp о том, что дизайнеры сделали этот выбор, чтобы предотвратить непреднамеренное обезьян с этим событием. Кажется, что, очевидно, плохо разрешать не связанные типы (типы, не полученные из типа, объявляющего событие) делать это, но даже для производных типов это может быть нежелательно. Они, вероятно, должны были бы включить синтаксис, чтобы позволить декларации события private или же protected Что касается использования в стиле в поле, так что я предполагаю, что они решили просто запретить его полностью.

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top