/// <summary> /// Publish the specified change record to all <see cref="Subscribers"/>. /// </summary> /// <param name="changeRecord">The change record to publish.</param> /// <exception cref="ArgumentNullException"><paramref name="changeRecord"/> is <see langword="null" />.</exception> public void Publish(ChangeRecord changeRecord) { if (changeRecord == null) { throw new ArgumentNullException(nameof(changeRecord)); } // local snapshot of subscribers ISubscription[] subscribers; lock (_subscribers) subscribers = _subscribers.ToArray(); // notify all subscribers that are active and match filter var deadSubscribers = subscribers .Where(h => IsMatch(changeRecord, h.Filter)) .Where(h => !h.BeginInvoke(changeRecord)) .ToList(); if (deadSubscribers.Count == 0) { return; } // remove dead subscribers lock (_subscribers) foreach (var d in deadSubscribers) { _subscribers.Remove(d); } }
private bool IsMatch(ChangeRecord changeRecord, string filter) { if (string.IsNullOrWhiteSpace(filter)) { return(true); } return(changeRecord.Namespace.Like(filter)); }
/// <summary> /// Begin invoke of <see cref="Handler"/> on the thread-pool background thread. /// </summary> /// <param name="change">The change record to send.</param> /// <returns><c>true</c> if the Handler is still alive and was able to be invoked; otherwise <c>false</c>.</returns> public bool BeginInvoke(ChangeRecord change) { // handler might have been disposed var handler = _reference.Target as IHandleChange; if (handler == null) { return(false); } // fire and forget return(ThreadPool.QueueUserWorkItem(state => handler.HandleChange(change))); }