我有一个List,这个SomeAttachmentClass有一个UploadCompleted事件,在调用.Save()方法时,只引发一次。保存并因此上传实际完成后,.Save()方法不会阻塞,但会立即返回并通过所述事件发出完成信号。
现在我想要和需要做的就是等待List<>中的所有实例提起那个事件(确切地说)一次然后才继续......&问题是 - 我将如何最简单/优雅地做到这一点?
我在考虑在每个实例上使用RX的FromEvent(..)和.Take(1),对所有这些实例流执行.SelectMany()并等待...但是我我不确定那里是否有更好的办法。
答案 0 :(得分:2)
这可以解决问题 - 感谢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;
}
答案 1 :(得分:1)
这是一个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;
}