我有一个列表,这个SomeAttachmentClass有一个UploadCompleted事件,在调用. save()方法时,只引发一次。. save()方法在保存和上传实际完成之前不会阻塞,而是立即返回并通过所述事件发出完成信号。
现在我想要和需要做的基本上是等待列表<>中的所有实例(确切地)引发该事件一次,然后继续…,问题是,我怎样才能做到最简单/最优雅?
我正在考虑在每个实例上使用RX的FromEvent(…)与。take(1)相结合,在所有这些每个实例流上执行。selectmany()并等待…但我不确定是否有更好的方法。
这可以解决这个问题-感谢Shlomo作为起点。
void Main()
{
Func<SomeAttachment, IObservable<object>> save = sa =>
Observable.Create<object>(o =>
{
var ob =
Observable
.FromEventPattern<object>(
eh => sa.UploadCompleted += eh,
eh => sa.UploadCompleted -= eh)
.Take(1)
.Select(x => x.EventArgs);
var subscription = ob.Subscribe(o);
sa.Save();
return subscription;
});
var list = Enumerable.Range(0, 10).Select(i => new SomeAttachment(i)).ToList();
list
.ToObservable()
.SelectMany(o => save(o))
.ToArray()
.Subscribe(_ => Console.WriteLine("All Complete. Handling logic goes here."));
}
public class SomeAttachment
{
private static Random random = new Random();
private readonly int _id;
public SomeAttachment(int id)
{
_id = id;
}
public int Id
{
get { return _id; }
}
public async Task Save()
{
//await Task.Delay(TimeSpan.FromMilliseconds(random.Next(1000, 3000)));
UploadCompleted?.Invoke(this, new object());
}
public event EventHandler<object> UploadCompleted;
}
这是一个Rx实现。你不需要等待,Rx会为你做的。注释掉的行用于在LinqPad中调试/运行:
void Main()
{
var list = Enumerable.Range(0, 10).Select(i => new SomeAttachment(i)).ToList();
list.ToObservable()
.Do(sa => sa.Save())
//.Do(sa => Console.WriteLine($"{sa.Id}: Save called"))
.Select(sa => Observable.FromEventPattern<object>(eh => sa.UploadCompleted += eh, eh => sa.UploadCompleted -= eh))
.SelectMany(o => o.Take(1))
//.Do(o => Console.WriteLine($"{(o.Sender as SomeAttachment).Id}: Upload completed."))
.All(_ => true)
.Take(1)
.Subscribe(_ => Console.WriteLine("All Complete. Handling logic goes here."));
}
// Define other methods and classes here
public class SomeAttachment
{
private static Random random = new Random();
private readonly int _id;
public SomeAttachment(int id)
{
_id = id;
}
public int Id
{
get { return _id; }
}
public async Task Save()
{
await Task.Delay(TimeSpan.FromMilliseconds(random.Next(1000, 3000)));
UploadCompleted?.Invoke(this, new object());
}
public event EventHandler<object> UploadCompleted;
}