Существует ли оборотная сторона к добавлению анонимного пустого делегата на объявлении события?

82
задан Community 23 May 2017 в 12:18
поделиться

7 ответов

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

36
ответ дан Maurice 24 November 2019 в 09:16
поделиться

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

public static void Raise(this EventHandler handler, object sender, EventArgs e)
{
    if(handler != null)
    {
        handler(sender, e);
    }
}

Когда-то определенный, Вы никогда не должны делать другую пустую проверку события снова:

// Works, even for null events.
MyButtonClick.Raise(this, EventArgs.Empty);
46
ответ дан Community 24 November 2019 в 09:16
поделиться

Для систем, которые делают интенсивное использование событий и являются критические по отношению к производительности , Вы определенно захотите к [по крайней мере 112], рассматривают не выполнение этого. Стоимость для того, чтобы сгенерировать событие с пустым делегатом является примерно дважды этим для повышения его с пустой проверкой сначала.

Вот некоторые числа, выполняющие сравнительные тесты на моей машине:

For 50000000 iterations . . .
No null check (empty delegate attached): 530ms
With null check (no delegates attached): 249ms
With null check (with delegate attached): 452ms

И вот код, я раньше получал эти числа:

using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        public event EventHandler<EventArgs> EventWithDelegate = delegate { };
        public event EventHandler<EventArgs> EventWithoutDelegate;

        static void Main(string[] args)
        {
            //warm up
            new Program().DoTimings(false);
            //do it for real
            new Program().DoTimings(true);

            Console.WriteLine("Done");
            Console.ReadKey();
        }

        private void DoTimings(bool output)
        {
            const int iterations = 50000000;

            if (output)
            {
                Console.WriteLine("For {0} iterations . . .", iterations);
            }

            //with anonymous delegate attached to avoid null checks
            var stopWatch = Stopwatch.StartNew();

            for (var i = 0; i < iterations; ++i)
            {
                RaiseWithAnonDelegate();
            }

            stopWatch.Stop();

            if (output)
            {
                Console.WriteLine("No null check (empty delegate attached): {0}ms", stopWatch.ElapsedMilliseconds);
            }


            //without any delegates attached (null check required)
            stopWatch = Stopwatch.StartNew();

            for (var i = 0; i < iterations; ++i)
            {
                RaiseWithoutAnonDelegate();
            }

            stopWatch.Stop();

            if (output)
            {
                Console.WriteLine("With null check (no delegates attached): {0}ms", stopWatch.ElapsedMilliseconds);
            }


            //attach delegate
            EventWithoutDelegate += delegate { };


            //with delegate attached (null check still performed)
            stopWatch = Stopwatch.StartNew();

            for (var i = 0; i < iterations; ++i)
            {
                RaiseWithoutAnonDelegate();
            }

            stopWatch.Stop();

            if (output)
            {
                Console.WriteLine("With null check (with delegate attached): {0}ms", stopWatch.ElapsedMilliseconds);
            }
        }

        private void RaiseWithAnonDelegate()
        {
            EventWithDelegate(this, EventArgs.Empty);
        }

        private void RaiseWithoutAnonDelegate()
        {
            var handler = EventWithoutDelegate;

            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }
}
42
ответ дан Kent Boogaart 24 November 2019 в 09:16
поделиться

При выполнении его / партия / Вы могли бы хотеть иметь единственного, статического/общего пустого делегата, которого Вы снова используете, просто для сокращения объема экземпляров делегата. Обратите внимание, что компилятор кэширует этого делегата на событие так или иначе (в статическом поле), таким образом, это - только один экземпляр делегата на определение события, таким образом, это не огромно сохранение - но возможно стоящий.

на поле экземпляра в каждом классе все еще займет то же место, конечно.

т.е.

internal static class Foo
{
    internal static readonly EventHandler EmptyEvent = delegate { };
}
public class Bar
{
    public event EventHandler SomeEvent = Foo.EmptyEvent;
}

, Кроме которого, это кажется прекрасным.

7
ответ дан Marc Gravell 24 November 2019 в 09:16
поделиться

Это - мое понимание, что пустой делегат ориентирован на многопотоковое исполнение, тогда как пустая проверка не.

2
ответ дан Christopher Bennage 24 November 2019 в 09:16
поделиться

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

MyEvent(this, EventArgs.Empty);

, Если клиент выдает исключение, сервер идет с ним.

Таким образом, возможно, Вы делаете:

try
{
  MyEvent(this, EventArgs.Empty);
}
catch
{
}

, Но, если у Вас есть несколько подписчиков и один подписчик, выдает исключение, что происходит с другими подписчиками?

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

// Usage
EventHelper.Fire(MyEvent, this, EventArgs.Empty);


public static void Fire(EventHandler del, object sender, EventArgs e)
{
    UnsafeFire(del, sender, e);
}
private static void UnsafeFire(Delegate del, params object[] args)
{
    if (del == null)
    {
        return;
    }
    Delegate[] delegates = del.GetInvocationList();

    foreach (Delegate sink in delegates)
    {
        try
        {
            sink.DynamicInvoke(args);
        }
        catch
        { }
    }
}
2
ответ дан Scott P 24 November 2019 в 09:16
поделиться

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

0
ответ дан Community 24 November 2019 в 09:16
поделиться
Другие вопросы по тегам:

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