I'm trying to come to grips with Reactive Extensions, but so far I just don't get it. So, I figured I'd try some exercises to get started. The "Hello World!" type examples from rxkoans.codeplex.com are pretty straightforward, so that makes me happy. But then, when I want to do something more complicated, it feels like I don't get this paradigm at all yet...
I found this question closest to what I want to try: How to do I show progress when using Reactive Extensions in C#
Now, suppose I wanted some progress reporting on processing an unknown number of items in some expensive manner. Furthermore, I don't want just the last item in the calculation in my observable but I want all intermediate results. For the sake of keeping it simple at first, I just took an existing example and first got the intermediate results up and running:
[TestMethod]
public void TODO2()
{
string result = "";
Calculate2().Subscribe(r => result += r.Result);
Assert.AreEqual("do1do2do3do1", result);
// PASSES
}
public IObservable<ResultWithProgress<string>> Calculate2()
{
return Observable.Create<ResultWithProgress<string>>(obs =>
{
Action<int, string, string> report = (pv, r, pt) =>
{
obs.OnNext(new ResultWithProgress<string>()
{
Progress = pv,
Result = r,
ProgressText = pt,
});
};
var query =
from result1 in Observable.Start(() => Do1()) // Just returns string "do1"
.Do(x => report(25, x, "Completed Task1"))
from result2 in Observable.Start(() => Do2()) // "do2"
.Do(x => report(50, x, "Completed Task2"))
from result3 in Observable.Start(() => Do3()) // "do3"
.Do(x => report(75, x, "Completed Task3"))
from result4 in Observable.Start(() => Do1()) // "do1" again
select new ResultWithProgress<string>()
{
Progress = 100,
Result = result4,
ProgressText = "Done!",
};
return query.Subscribe(obs);
});
}
Then, I figured I'd tackle the fact that I don't have a fixed number of elements/calculations. I started with an array of 4 elements for now, but it could be any number. I don't know beforehand, it's going to be a lazy sequence.
[TestMethod]
public void TODO3()
{
string result = "";
Calculate3().Subscribe(r => result += r.Result);
Assert.AreEqual("do1do2do3do1", result);
// Doesn't compile yet, see below...
}
public IObservable<ResultWithProgress<string>> Calculate3()
{
return Observable.Create<ResultWithProgress<string>>(obs =>
{
Action<int, string, string> report = (pv, r, pt) =>
{
obs.OnNext(new ResultWithProgress<string>()
{
Progress = pv,
Result = r,
ProgressText = pt,
});
};
int[] bla = new int[] { 1, 2, 3, 4 };
foreach(var b in bla)
{
Observable.Start(() => "BLAH" /* expensive operation here in the future */)
.Do(x => report(25 * b, x, "Completed Task1"));
}
// Completed!
obs.OnCompleted();
// I want an Observable that emits "BLAH" four times
// and then signals that it is completed
// What do I return here?
return ?????;
});
}
I'm sure this is just my lack of understanding of Rx, I just started with it. Could someone please help me wrap my mind around what I should be doing to get a stream of results when you don't have a fixed number of operations?
Thank you kindly.