2016-12-07 4 views
0

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

Глядя на него атомарно я смог добиться этого, используя следующие:

private bool _wasEventCalled; 
private event Action _someEvent; 

public event Action SomeEvent 
{ 
    add 
    { 
     if (value == null) 
     { 
      return; 
     } 

     // If already called, call immediatley 
     if (_wasEventCalled) 
     { 
      value(this); 
      return; 
     } 
     _someEvent += value; 
    } 
    remove 
    { 
     if (_someEvent == null) 
     { 
      return; 
     } 
     _someEvent -= value; 
    } 
} 


private void InvokeEvent() 
{ 
    _wasEventCalled = true; 
    _someEvent.Invoke(); 
} 

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

+0

'_someEvent.Invoke();' должен быть '_someEvent? .Invoke();' обрабатывать случай, когда нет обработчиков. Кроме того, этот код работает неправильно, если его вызывает несколько потоков; по-видимому, это не такая ситуация, с которой вам нужно обращаться, и только один поток, воздействующий на этот объект за раз. Это верно? – Servy

+0

@Servy это был полу-псевдокод - мой вопрос больше о том, как я могу достичь этого в многоразовом режиме, если я хочу, чтобы это поведение происходило на нескольких событиях, а безопасность потоков не является проблемой. – Ron

+0

удаляет ручки что-то что вам действительно нужно? – Servy

ответ

0

Что вы описываете, это более или менее продолжение Task продолжений, так что вы можете просто контрейлерировать на Task.

private TaskCompletionSource<bool> someEventSource = 
    new TaskCompletionSource<bool>(); 

public event Action SomeEvent 
{ 
    add 
    { 
     someEventSource.Task.ContinueWith(t => value?.Invoke()); 
    } 
    remove 
    { 
     throw new NotImplementedException(); 
    } 
} 


private void InvokeEvent() 
{ 
    someEventSource.TrySetResult(true); 
} 

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

+0

Теперь я понимаю, почему вы спросили, что, хотя это будет работать - мы работаем с Unity3d, который использует старую версию .NET (нет задач). Кроме того, я хотел остаться с соглашением делегатов + = – Ron

+0

@Ron Тогда вам нужно создать свой собственный класс. Это было бы непросто, в основном просто рефакторинг каждой операции в ее собственный метод, используя уже существующие реализации. – Servy

+0

, так что я тоже это сделал, перегружая операторов + и -. Моя проблема с этим подходом заключается в следующем: 1. Для этого требуется инстанция класса 2. Событие может вызываться из любого места, так как теперь это класс, а не делегат события. Интеллект MSVS не очень хорошо работает с этим решением. – Ron

Смежные вопросы