.NET: Создание новых EventArgs каждый раз, когда событие запускается, хорошая практика? - PullRequest
8 голосов
/ 29 января 2010

Например, у меня есть метод публикации базовых событий:

    protected virtual OnSomeEvent(EventArgs e)
    {
        var handler = SomeEvent;
        if (handler != null)
        {
            handler(this, e);
            // handler(this, new EventArgs());// EDIT: Yes it should be
                                           // handler(this, e),
                                           // ignore this one :D
        }
    }

Для производного класса, который переопределяет OnSomeEvent и вызывает дополнительное событие при его запуске:

    protected override OnSomeEvent(EventArgs e)
    {
        base.OnSomeEvent(e);

        if (ExtendedEvent != null)
        {
            OnExtendedEvent(e);
        }
    }

    protected void OnExtendedEvent(EventArgs e)
    {
       // some stuff done
       // new information the ExtendedEventArgs object needs 
       //  is not available until this point

       ExtendedEvent(this, new ExtendedEventArgs(someStuff, someOtherStuff));
    }

И если деривация будет продолжаться таким образом, она создаст новый производный EventArgs для каждого поколения производного класса, которому это требуется. Однако, похоже, что различные производные EventArgs в .NET Framework не предназначены для изменчивости (без установщиков), это препятствует объекту сохранять один экземпляр EventArgs и модифицировать его по мере необходимости.

Таким образом, каждый раз, когда происходит подобное событие, оно перераспределяет память для всех задействованных EventArgs объектов. В графическом интенсивном приложении, где событие может запускаться десятки раз в секунду (например, событие OnPaint на элементе управления), действительно ли это хорошая практика?

Должен ли я внести некоторые изменения в OnExtendedEvent() и сделать изменяемым ExtendedEventArgs, чтобы было возможно следующее?

    protected ExtendedEventArgs extendedArgs = ExtendedEventArgs.Empty;
    protected void OnExtendedEvent(EventArgs e)
    {
       // some stuff done
       // new information the ExtendedEventArgs object needs 
       //  is not available until this point

       extendedArgs.someProperty1 = someStuff;
       extendedArgs.someProperty2 = someOtherStuff;

       ExtendedEvent(this, extendedArgs);
    }

РЕДАКТИРОВАТЬ: Исправлен пример кода, теперь должен быть яснее.

Ответы [ 3 ]

5 голосов
/ 29 января 2010

Прежде всего, зачем передавать аргумент EventArgs в ваш метод запуска, если вы все равно его просто игнорируете? Это реальная трата, но потребление ресурсов менее проблематично, чем ложь, которую ваш метод говорит своим вызывающим. Просто передайте аргумент до конца, ваш метод запуска, скорее всего, не будет иметь доступ к соответствующей информации для создания объекта EventArgs:

protected virtual OnSomeEvent(EventArgs e)
{
    var handler = SomeEvent;
    if (handler != null)
    {
        handler(this, e);
    }
}

Итак, теперь, когда у нас все в порядке, если у вашего объекта EventArgs нет значимой информации, чтобы сообщить своим подписчикам, просто используйте EventArgs.Empty, вот для чего он нужен. Вы можете следовать тому же шаблону для своих пользовательских классов EventArgs, но, честно говоря, вы ни о чем не беспокоитесь. Создание объектов EventArgs никогда не будет узким местом в вашем приложении, и если это так, у вас есть проблемы с дизайном.

3 голосов
/ 29 января 2010

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

Основная причина в том, что произойдет, если новое событие будет запущено снова во время обработки существующего события?

Это может произойти в многопоточных приложениях, но может даже произойти в одном потоке, как показано в следующем примере:

Первое событие запускается со следующими значениями:

extendedArgs.someProperty1 = "Fire 1";
extendedArgs.someProperty2 = "Fire 1 Other Stuff";

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

extendedArgs.someProperty1 = "Fire 2";
extendedArgs.someProperty2 = "Fire 2 Other Stuff";

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

Теперь, поскольку используется один и тот же объект, все обработчики событий для первого события теперь будут иметь "Fire 2" в качестве someProperty1, поскольку второе событие перезаписывает значения.

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

1 голос
/ 29 января 2010

Я немного озадачен вашим OnExtendedEvent кодом - вы хотите повторно отправить событие как SomeEvent?

Когда клиент добавляет обработчик события, он ожидает, что сможет удалить обработчик события во время обработки события, например:

someObject.SomeEvent += OnSomeEvent;
// ...
private void OnSomeEvent(object sender, EventArgs e)
{
    someObject.SomeEvent -= OnSomeEvent;
}

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

...