В каких случаях было бы полезно использовать событие, не поддерживая его переменной делегата? - PullRequest
0 голосов
/ 14 марта 2011

Я читаю эту статью Джона Скита как часть моего стремления получить глубокое понимание делегатов и событий.

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

... бывают случаи, когда вы не хотите поддержать событие простым делегатом переменная. Например, в ситуациях где много событий, но только немногие могут быть подписаны чтобы вы могли иметь карту из какого-то ключа Описание события делегату в данный момент справляюсь. Это то, что Windows Forms - это означает, что вы может иметь огромное количество событий не тратя много памяти с переменные, которые обычно будут просто иметь нулевые значения.

Я не до конца понимаю, что он говорит. Может кто-нибудь конкретизировать примеры? Например, что он имеет в виду, имея «карту из некоторого ключа, описывающего событие, для делегата, который в настоящее время его обрабатывает»? Как Windows Forms делает это?

Спасибо!

Ответы [ 3 ]

5 голосов
/ 14 марта 2011

Вы можете использовать тот же тип самостоятельно - EventHandlerList.Предположим, у вас есть 100 событий - это обычно означало бы иметь 100 переменных, которые занимали бы место, даже если никто не подписывался на событие.Вместо этого EventHandlerList представляет собой бит , как Dictionary<object, EventHandler> - он создает запись во внутренних структурах данных только при первой подписке на определенное событие.есть что-то вроде:

// Actual values don't matter; they're just keys
private const string FirstEventKey = "FirstEvent";
private const string SecondEventKey = "SecondEvent";

private readonly EventHandlerList events = new EventHandlerList();

public event EventHandler FirstEvent
{
    add { events.AddHandler(FirstEventKey, value); }
    remove { events.RemoveHandler(FirstEventKey, value); }
}

public event EventHandler SecondEvent
{
    add { events.AddHandler(SecondEventKey, value); }
    remove { events.RemoveHandler(SecondEventKey, value); }
}

public void OnFirstEvent(EventArgs e)
{
    EventHandler handler = (EventHandler) events[FirstEventKey];
    if (handler != null)
    {
        handler(this, e);
    }
}

// Similarly for OnSecondEvent
0 голосов
/ 27 августа 2011

Другая ситуация - тривиальный случай, когда базовый класс или интерфейс предоставляют событие для чего-то, что никогда не произойдет в определенных производных типах. Например, интерфейс observable-collection только для чтения может предоставлять CollectionChangedEvent. Объект, содержащий переменную интерфейса, не сможет использовать ее для изменения коллекции, но может быть заинтересован в том, чтобы узнать, если / когда что-то еще изменит коллекцию. Такая сущность должна быть в состоянии использовать неизменную коллекцию так же, как изменяемую; с ее точки зрения, неизменяемая коллекция должна быть похожа на изменяемую коллекцию, которую никто не потрудит мутировать во время просмотра.

Наиболее логичной реализацией CollectionChangedEvent было бы иметь методы add- и remove-handler, которые ничего не делают, без вспомогательного поля делегата. Внешняя сущность, которая вызывает метод add-handler, по сути, говорит «Позвоните мне, если эта коллекция изменится». Когда он вызывает метод remove-handler, он по сути говорит: «Мне больше не нужно знать, изменяется ли эта коллекция». Если коллекция никогда не изменится, эти запросы можно выполнить, просто ничего не делая.

0 голосов
/ 15 марта 2011

Я хотел бы добавить, что это то, что я видел довольно часто

// bad code
class MyControl : Control {
    public event EventHandler ValueChanged;

    private CheckBox checked;
    // ...

    private void InitializeComponent() {
        // ...
        checked.CheckedChanged += checked_CheckedChanged;
        // ...
    }

    private void checked_CheckedChanged(object sender, EventArgs e) {
        if (ValueChanged != null) {
            ValueChanged(sender, e);
        }
    }
}

Я считаю это анти-паттерном, потому что этот способ быстрее, занимает меньше памяти и в целом проще, я думаю:

class MyControl : Control {
    public event EventHandler ValueChanged {
        add {
            checked.CheckChanged += value;
        }
        remove {
            checked.CheckChanged -= value;
        }
    }

    private CheckBox checked;
    // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...