События Raising C# с дополнительным методом - являются этим плохо?

Мы все знакомы с ужасом, который является объявлением события C#. Для обеспечения потокобезопасности стандарт должен записать что-то вроде этого:

public event EventHandler SomethingHappened;
protected virtual void OnSomethingHappened(EventArgs e)
{            
    var handler = SomethingHappened;
    if (handler != null)
        handler(this, e);
}

Недавно в некотором другом вопросе на этой плате (который я не могу найти теперь), кто-то указал, что дополнительные методы могли использоваться приятно в этом сценарии. Вот один способ сделать это:

static public class EventExtensions
{
    static public void RaiseEvent(this EventHandler @event, object sender, EventArgs e)
    {
        var handler = @event;
        if (handler != null)
            handler(sender, e);
    }
    static public void RaiseEvent(this EventHandler @event, object sender, T e)
        where T : EventArgs
    {
        var handler = @event;
        if (handler != null)
            handler(sender, e);
    }
}

С этими дополнительными методами на месте, все необходимо объявить и сгенерировать событие, что-то вроде этого:

public event EventHandler SomethingHappened;

void SomeMethod()
{
    this.SomethingHappened.RaiseEvent(this, EventArgs.Empty);
}

Мой вопрос: действительно ли это - хорошая идея? Мы пропускаем что-нибудь, не имея стандарт На методе? (Одна вещь, которую я замечаю, состоит в том, что это не работает с событиями, которые имеют явный, добавляет/удаляет код.)

50
задан Bill Tarbell 18 July 2019 в 03:55
поделиться

4 ответа

Это будет все еще работать с событиями, которые имеют явное, добавляют/удаляют - просто необходимо использовать переменную делегата (или однако Вы сохранили делегата) вместо имени события.

Однако существует более легкий способ сделать, он ориентированный на многопотоковое исполнение - инициализирует его ни с каким-op обработчиком:

public event EventHandler SomethingHappened = delegate {};

хит производительности вызова дополнительного делегата будет незначителен, и это уверенный делает код легче.

Между прочим, в Вашем дополнительном методе Вам не нужна дополнительная локальная переменная - Вы могли просто сделать:

static public void RaiseEvent(this EventHandler @event, object sender, EventArgs e)
{
    if (@event != null)
        @event(sender, e);
}

static public void RaiseEvent<T>(this EventHandler<T> @event, object sender, T e)
    where T : EventArgs
{
    if (@event != null)
        @event(sender, e);
}

Лично я не использовал бы ключевое слово в качестве названия параметра, но это действительно не изменяет сторону вызова вообще, сделайте то, что Вы хотите:)

РЕДАКТИРОВАНИЕ: Что касается метода "OnXXX": Вы - планирование Ваших классов, получаемых из? По моему мнению, большинство классов должно быть изолировано. Если Вы делаете , Вы хотите, чтобы те производные классы были в состоянии сгенерировать событие? Если ответ на любой из этих вопросов является "нет", тогда не беспокоятся. Если ответ обоим - "да", тогда сделайте:)

56
ответ дан Jon Skeet 7 November 2019 в 11:01
поделиться

[Вот мысль]

, Просто пишут код однажды рекомендуемым способом и делаются с ним. Тогда Вы не смутите своих коллег, просматривающих код, думая, что Вы сделали что-то не так?

[я прочитал больше сообщений, пытающихся находить способы вокруг записи обработчика событий, чем я когда-нибудь трачу запись обработчика событий.]

5
ответ дан Robert Paulson 7 November 2019 в 11:01
поделиться

Меньше кода, более читаемого. Я как.

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

public event EventHandler SomethingHappened = delegate{};
3
ответ дан Cristian Libardo 7 November 2019 в 11:01
поделиться

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

Вы сохраняете себя от исключения нулевой ссылки, но существуют более легкие способы сделать это как Jon Skeet и cristianlibardo, на который указывают в их ответах.

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

1
ответ дан Isak Savo 7 November 2019 в 11:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: