Как правильно не зарегистрировать обработчик событий

Не используйте разделители регулярных выражений:

name = Regex.Replace(name, @"\W", "");

В C # вы не можете использовать разделители регулярных выражений, поскольку синтаксис объявления обычного выражения отличается от синтаксиса PHP, Perl или JavaScript или других, которые поддерживают <action>/<pattern>(/<substituiton>)/modifiers regex.

Просто, чтобы избежать путаницы в терминологии: встроенные модификаторы (принудительный поиск без учета регистра, многострочный, одинарный, многословный и другие режимы), безусловно, поддерживаются и могут использоваться вместо соответствующих флагов RegexOptions (хотя число возможных флагов RegexOptions выше, чем число встроенных модификаторов). Тем не менее, regex delimiters вообще не влияют на шаблон регулярного выражения, они являются лишь частью синтаксиса объявления и не влияют на сам шаблон. Скажем, они являются просто альтернативой для ; или строк, разделяющих строки новой строки.

В C # разделители регулярных выражений не нужны и, следовательно, не поддерживаются. Perl-стиль s/\W//g будет записан как var replaced = Regex.Replace(str, @"\W", string.Empty);. И так далее.

64
задан Noldorin 2 October 2009 в 12:59
поделиться

2 ответа

Реализация по умолчанию компилятора C# добавления обработчика событий звонит Delegate.Combine, в то время как удаление обработчика событий звонит Delegate.Remove:

Fire = (MyDelegate) Delegate.Remove(Fire, new MyDelegate(Program.OnFire));

реализация Платформы Delegate.Remove не смотрит эти MyDelegate сам объект, но в методе делегат обращается к (Program.OnFire). Таким образом совершенно безопасно создать новое MyDelegate объект при отмене подписки существующего обработчика событий. Из-за этого компилятор C# позволяет Вам использовать синтаксис стенографии (который генерирует точно тот же код негласно) при добавлении/удалении обработчиков событий: можно опустить new MyDelegate часть:

Fire += OnFire;
Fire -= OnFire;

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

MyDelegate handler = Fire;
if (handler != null)
    handler("Hello 3");

Это присвоено временной локальной переменной для защиты от возможного состояния состязания с отказывающимися от подписки обработчиками событий на других потоках. (См. мое сообщение в блоге для получения дополнительной информации о потокобезопасности присвоения обработчика событий к локальной переменной.) Другой способ защитить от этой проблемы состоит в том, чтобы создать пустого делегата, который всегда подписывается; в то время как это использует немного больше памяти, обработчик событий никогда не может быть пустым (и код может быть более простым):

public static event MyDelegate Fire = delegate { };
82
ответ дан Bradley Grainger 24 November 2019 в 15:56
поделиться

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

public event MyDelegate Fire = delegate {};

Однако это - просто взлом для ухода от NullReferenceExceptions.

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

public event MyDelegate Fire;
public void FireEvent(string msg)
{
    MyDelegate temp = Fire;
    if (temp != null)
        temp(msg);
}

, К сожалению, JIT-компилятор может оптимизировать код, устранить временную переменную и использовать исходного делегата. (согласно Juval Lowy - Программирование Компонентов.NET)

Так для предотвращения этой проблемы Вы могли использовать метод, который принимает делегата как параметр:

[MethodImpl(MethodImplOptions.NoInlining)]
public void FireEvent(MyDelegate fire, string msg)
{
    if (fire != null)
        fire(msg);
}

Примечание, которые без MethodImpl (NoInlining) приписывают JIT-компилятор, могло встроить метод, делающий его бесполезный. Так как делегаты неизменны, эта реализация ориентирована на многопотоковое исполнение. Вы могли использовать этот метод как:

FireEvent(Fire,"Hello 3");
15
ответ дан user37325 24 November 2019 в 15:56
поделиться
Другие вопросы по тегам:

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