(A)等待多个实例将事件恰好提升一次

时间:2016-09-08 08:12:23

标签: c# events task-parallel-library system.reactive

我有一个List,这个SomeAttachmentClass有一个UploadCompleted事件,在调用.Save()方法时,只引发一次。保存并因此上传实际完成后,.Save()方法不会阻塞,但会立即返回并通过所述事件发出完成信号。

现在我想要和需要做的就是等待List<>中的所有实例提起那个事件(确切地说)一次然后才继续......&问题是 - 我将如何最简单/优雅地做到这一点?

我在考虑在每个实例上使用RX的FromEvent(..)和.Take(1),对所有这些实例流执行.SelectMany()并等待...但是我我不确定那里是否有更好的办法。

2 个答案:

答案 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;

}