Страница: 1 |
|
Вопрос: Обработка try-catch только верхнего уровня
|
Добавлено: 08.05.12 14:38
|
|
Автор вопроса: Programmer
|
Допустим, существует такой код:
try{
TestEvent();
}catch (NullReferenceException) { }
TestEvent может быть равно null. Проверять через if - нельзя.
Существует ли способ обрабатывать только исключение, когда TestEvent = null, но пропускать его, если возникает внутри TestEvent?
Ответить
|
Номер ответа: 6 Автор ответа: Artyom
Разработчик
Вопросов: 130 Ответов: 6602
|
Профиль | | #6
|
Добавлено: 13.05.12 11:59
|
Вот код, код гарантированно (Я ГАРАНТИРУЮ ЭТО) безопасной генерации события. Не упадет если SomeEvent равен null (т.е. на него никто не подписался), если во время проверок кто-то подпишется, отпишется, или произойдет что-то еще.
- public event EventHandler SomeEvent;
-
- public void OnSomeEvent()
- {
- EventHandler handler = (EventHandler)Thread.VolatileRead(ref this.SomeEvent);
- if (handler != null)
- {
- handler(this, EventArgs.Empty);
- }
AgentFire пишет:
распространенная проблема. при объявлении евента допиши в конце
= delegate { }
говнокод
Programmer пишет:
Если скопировать список делегатов, есть вероятность вызвать отписанное событие.
Типы Delegate, MulticastDelegate (коим, собственно, и является EventHandler) - immutable типы. Это значит что после создания они не могут изменяться.
Если кто-то хочет добавить в цепочку вызовов еще один обработчик (т.е. грубо говоря подписаться на событие), или удалить обрабочтик (отписаться), то создается новый экземпляр типа Delegate, в содержащий модифицированную цепочку обрабочтиков (или null, если из цепочки удалены все обработчики). И этот экземпляр ложится в поле класса, хранящее ссылку на обработчик события.
Аналогично работает тип String. Когда ты модифицируешь строк (например, добавляшеь в конец один символ), создается новый экземпляр строки с добавленным в конец символом. Старый же остается без изменений. С этим как раз связаны потенциальные тормоза если производить много модификаций с обычными String, и поэтому для таких действий рекомендуется использовать muttable StringBuilder.
Копирование ссылки в дотнете - это атомарная операция. Если какой-то другой поток модифицирует ссылку, то копирование будет гарантированно выполнено до или после этой модификации.
Таким образом, если ты скопировал из поля в переменную ссылку на объект, а потом другой поток в это поле положил null, в твоей переменной останется корректная ссылка на старое значение поля. И ты можешь абсолютно безопасно делать проверку на null и вызывать событие.
Использование VolatileRead для чтения значения из поля позволяет избежать проблем, связанных с тем, что на этапе JIT компиляции к коду могут быть применены оптимизации, которые изменят порядок операций (например, проверка ссылки на null будет выполнена до того как она будет скопирована).
Но если учесть что при обращении к обрабочтику события JIT такие оптимизации не использует, то можно писать и так
- public event EventHandler SomeEvent;
-
- public void OnSomeEvent()
- {
- EventHandler handler = this.SomeEvent;
- if (handler != null)
- {
- handler(this, EventArgs.Empty);
- }
принимая во внимание кол-во кода, написанного на данный момент в таком стиле, можно с смело предполагать что в дальнейшем поведение оптимизатора в этих случаях не будут изменять.
=====================================================
Как я понимаю, твое событие объявлено без параметров типа
- public delegate void MyEventDelegate();
-
- public event MyEventDelegate MyEvent;
Если так, это нарушение конвенции сигнатуры событий в .NET. События должны иметь тип EventHandler или EventHandler<T>. 2 параметра, первый - sender, второй - пустой EventArgs, или наследник от EventArgs, содержащий дополнительные параметры.
Ответить
|
Страница: 1 |
Поиск по форуму