假设我有一组我正在监控可用性的URI。每个URI都是“向上”或“向下”,并且可以随时向系统添加要监视的新URI:
public enum ConnectionStatus
{
Up,
Down
}
public class WebsiteStatus
{
public string Uri
{
get;
set;
}
public ConnectionStatus Status
{
get;
set;
}
}
public class Program
{
static void Main(string[] args)
{
var statusStream = new Subject<WebsiteStatus>();
Test(statusStream);
Console.WriteLine("Done");
Console.ReadKey();
}
private static void Test(IObservable<WebsiteStatus> statusStream)
{
}
}
现在假设Test()
我想反应性地确定:
bool
)IEnumerable<string>
)因此Test
最终会创建一个类似IObservable<Tuple<bool, IEnumerable<string>>>
的可观察对象,其中bool
表示所有URI都已关闭且IEnumerable<string>
包含那些URI。
我该如何解决这个问题?我最初的想法是,我需要按URI分组,然后将每个组中的最新组合成一个列表,然后我可以执行Select
反对。但是,由于CombineLatest
的工作方式,这种情况无法解决。
编辑:感谢Matthew的回答,我查看了rxx并发现它实现了一个CombineLatest
重载,完全按照我在rx开箱即期的方式实现,除了我需要更改它以便即使只有一个源流被组合时它也会发布(默认情况下,它等待至少两个源流)。此外,我无法为一种方法提供额外的2MB二进制文件,因此我将其复制/粘贴到我的项目中。这样做,我能够解决如下:
private static void Test(IObservable<WebsiteStatus> statusStream)
{
statusStream
.GroupBy(x => x.Uri)
.CombineLatest()
.Select(
x =>
{
var down = x.Where(y => y.Status == ConnectionStatus.Down);
var downCount = down.Count();
var downUris = down.Select(y => y.Uri).ToList();
return new
{
AllDown = x.Count == downCount,
DownUris = downUris
};
})
.Subscribe(x =>
{
Console.WriteLine(" Sources down ({0}): {1}", x.AllDown ? "that's all of them" : "some are still up", x.DownUris.Aggregate("", (y, z) => y += (z + " | ")));
});
}
答案 0 :(得分:4)
最好的方法是在this answer中使用Rxx扩展名。下面是另一种选择,它只是保留了一个向下/向上的网站列表。
var downStream = statusStream
.Aggregate<WebsiteStatus, IEnumerable<string>>(new string[0], (down, newStatus) =>
{
if (newStatus.IsUp)
return down.Where(uri => uri != newStatus.Uri);
else if (!down.Contains(newStatus.Uri))
return down.Concat(new string[] { newStatus.Uri });
else
return down;
});
var upStream = statusStream
.Aggregate<WebsiteStatus, IEnumerable<string>>(new string[0], (up, newStatus) =>
{
if (!newStatus.IsUp)
return up.Where(uri => uri != newStatus.Uri);
else if (!up.Contains(newStatus.Uri))
return down.Concat(new string[] { newStatus.Uri });
else
return up;
});
var allDown = upStream.Select(up => !up.Any());