In the following code if I understand joins in RX correctly, I should see the following alerts occur:
- West
- Test
- Test-West*
- Done
I get 3 of the 4 alerts I expect… why aren’t I receiving “Test-West” as well?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var loginInitial = new LoginInitial();
var loginCheckList = new LoginCheckList();
var result1 = from x in loginInitial.Status
from y in loginCheckList.Status
where x == "Test" && y == "West"
select new { x, y };
result1.Subscribe(x => MessageBox.Show(x.x + "-" + x.y));
var result2 = from x in loginInitial.Status
where x == "Test"
select x;
result2.Subscribe(x => MessageBox.Show(x));
var result3 = from x in loginCheckList.Status
where x == "West"
select x;
result3.Subscribe(x => MessageBox.Show(x));
var task1 = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 10000000; i++)
{
if (i == 9000000)
loginInitial.Status.Publish("9000000");
if (i == 9000001)
loginInitial.Status.Publish("Test");
}
});
var task2 = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 1000000; i++)
{
if (i == 800000)
loginInitial.Status.Publish("800000");
if (i == 800001)
loginCheckList.Status.Publish("West");
}
});
Task.WaitAll(task1, task2);
MessageBox.Show("Done");
}
}
public class LoginInitial
{
public PublishObservable<string> Status = new PublishObservable<string>();
}
public class LoginCheckList
{
public PublishObservable<string> Status = new PublishObservable<string>();
}
public class PublishObservable<T> : IObservable<T>
{
private IList<IObserver<T>> _observers = new List<IObserver<T>>();
public void Publish(T value)
{
lock (_observers)
{
foreach (var observer in _observers)
{
observer.OnNext(value);
}
}
}
public void Complete()
{
lock (_observers)
{
foreach (var observer in _observers)
{
observer.OnCompleted();
}
}
}
public IDisposable Subscribe(IObserver<T> observer)
{
lock (_observers)
{
_observers.Add(observer);
}
return null;
}
}
Tomas Petricek pretty much explains why this is happening. I’ll just add a solution as an example.
As well as adjusting result1 to use
CombineLatest(which also needs to use extension method syntax as opposed to linq syntax), I’ve changed the implementation to useSubjectwhich will remove the need to create your own implementation ofIObservable. I’ve also changed your implementations that uses multiple subscriptions into a single subscription by mergin geach result observable throughObservable.Merge.Note 1 – I’ve used
CombineLatesthere but you could just as easily change it to useZipdepending on the behavior you need. Check out the marble diagrams on the RxAs pages for Zip and CombineLatest for a better idea of how each behaves.Note 2 – I would probably change result2 and result3 to use extension method syntax so that there isn’t a mix of approaches in one method. Nothing wrong with it the way it is but I’d prefer the consistency of using one type of syntax where possible.