I created a simple set of interfaces and a class that allow me to publish the additions and removals of items in a generic dictionary. Subscribers receive the entire list when they subscribe and after that, they get only the changes.
Although my solutions work, I am looking for something a little more standard, a little less home-grown. Do you have any suggestions?
Notes on what I've found so far:
I have been looking at Microsoft's Reactive Extensions (Rx). According to Jon Skeet's article "LINQ to Rx: second impressions" [1], he says "as soon as an observer subscribes, the observable publishes everything in the sequence to it (on a different thread, by default). Separate calls to Subscribe make the observable iterate over the sequence multiple times." This sounds like the basic idea, but I can't find any specific examples and I'm not really sure about the thread-safety of "Subject" or "AsyncSubject" yet.
Notes on my home-grown solution:
The structure that is delivered to subscribers looks like this:
/// <summary>
/// Interface for a set of changes that are being published.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TItem"></typeparam>
public interface IPublication<TKey, TItem>
{
/// <summary>
/// Version of the list.
/// </summary>
long Version { get; }
/// <summary>
/// Items that were added or updated.
/// </summary>
IEnumerable<TItem> ChangedItems { get; }
/// <summary>
/// Keys to items that were removed.
/// </summary>
IEnumerable<TKey> RemovedKeys { get; }
}
The subscribers themselves must implement this interface:
/// <summary>
/// Interface for a subscriber that will receive IPublication{TKey, TItem} deliveries from a publisher.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TItem"></typeparam>
public interface ISubscribe<TKey, TItem>
{
void Deliver(IPublication<TKey, TItem> pub);
}
And of course my generic dictionary publisher class has this method:
/// <summary>
/// Adds the give subscriber to the list of subscribers and immediately publishes the
/// dictionary contents to the new subscriber. The return value may be disposed when
/// the subscriber wishes to terminate it's subscription.
/// </summary>
/// <param name="subscriber"></param>
/// <returns></returns>
public IDisposable Subscribe(ISubscribe<TKey, TItem> subscriber);
[1] http://msmvps.com/blogs/jon_skeet/archive/2010/01/19/linq-to-rx-second-impressions.aspx