我试图接触Reactive Extensions,但到目前为止我还没有得到它。所以,我想我会尝试一些练习来开始。 " Hello World!"来自rxkoans.codeplex.com的类型示例非常简单,所以这让我很开心。但是,当我想做一些更复杂的事情时,感觉就像我还没有得到这个范例......
我发现这个问题最接近我想要尝试的问题:How to do I show progress when using Reactive Extensions in C#
现在,假设我想要以某种昂贵的方式处理未知项目的进度报告。此外,我不想在我的观察中计算中的最后一项,但我想要所有中间结果。为了一开始保持简单,我只是采用了一个现有的例子,并首先得到了中间结果并运行:
[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);
});
}
然后,我想我应该解决这个问题,即我没有固定数量的元素/计算。我现在开始使用4个元素的数组,但它可以是任何数字。我事先不知道,这将是一个懒惰的序列。
[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 ?????;
});
}
我确定这只是我对Rx缺乏了解,我刚开始使用它。当你没有固定数量的操作时,是否有人可以帮助我了解我应该做些什么来获得结果?
谢天谢地。
答案 0 :(得分:1)
在第一个示例中,他们构建了一个查询,然后返回query.Subscribe(obs)
。这是正确的做法。
在您的代码中,您明确地将值传递给观察者。您可以这样做,但不建议这样做,因为它可能会创建阻止或行为不正确的查询。当某些事情在Rx中表现不正确时,很难解决。
正确的做法是:
public IObservable<ResultWithProgress<string>> Calculate3()
{
return Observable.Create<ResultWithProgress<string>>(obs =>
{
var query =
from b in new int[] { 1, 2, 3, 4 }.ToObservable()
from x in Observable.Start(() => "BLAH" /* expensive operation here in the future */)
select new ResultWithProgress<string>()
{
Progress = 25 * b,
Result = x,
ProgressText = "Completed " + b,
};
return query.Subscribe(obs);
});
}
但现在这只是一点点矫枉过正,所以这就足够了:
public IObservable<ResultWithProgress<string>> Calculate3()
{
return
from b in new int[] { 1, 2, 3, 4 }.ToObservable()
from x in Observable.Start(() => "BLAH" /* expensive operation here in the future */)
select new ResultWithProgress<string>()
{
Progress = 25 * b,
Result = x,
ProgressText = "Completed " + b,
};
}
简单是最好的。
唯一的另一个评论是你的专栏Observable.Start(() => "BLAH" /* expensive operation here in the future */).Do(x => report(25 * b, x, "Completed Task1"));
什么都不做。 Rx就像普通的可枚举一样,它被懒惰地评估,所以在订阅之前没有任何事情发生。