将基于事件的代码转换为Rx

Ala*_*ter 6 c# system.reactive

我有以下代码(简化用于发布目的).

public class SomeDataObject
{
    public delegate void ReadyEventHandler;
    public delegate void ErrorEventHandler;

    public event ReadyEventHandler Ready;
    public event ErrorEventHandler Error;
    ...
}

pubic class ConsumerClass
{
    private SomeDataObject dataObject;

    private Task<List<string>> GetStrings()
    {
        List<string> results = new List<string>();
        var tcs = new TaskCompletionSource<List<string>>();

        SomeDataObject.ReadyEventHandler ReadyHandler = null;
        SomeDataObject.ErrorEventHandler ErrorHandler = null;

        ReadyHandler += () =>
        {
            for (int i =0; i < dataObject.ItemCount; i++)
                results.Add(dataObject[i].ToString());

            tcs.TrySetResult(results);
        }

        ErrorHandler += ()
        {
            tcs.TrySetException(new Exception("oops!");
        }

        dataObject.Ready += ReadyHandler;
        dataObject.Error += ErrorHandler;

        dataObject.DoRequest();
    }
}
Run Code Online (Sandbox Code Playgroud)

我们的想法是,当进行DoRequest调用时,SomeDataObject将获取一些数据并引发Ready或Error事件(细节并不重要!).如果数据可用,则ItemCount指示可用的项目数.

我是Rx的新手,找不到任何类似的例子.那么是否可以将其转换为Rx,以便IObservable<string>返回而不是以Task<List<string>>某种方式使用Observable.Create?

关心艾伦

Lee*_*ell 6

马修的答案很接近但有一些问题.首先,它很渴望,这通常不符合Rx/Functional编程的精神.接下来我认为您将希望能够在消费者处置时释放事件句柄.最后一个主题的用法应该是一个代码气味,这个案例指出了上面的两个问题:-)

这里我用Observable.Create(这应该是在工具箱中的#1转到工具,与主题是你的最后一招)懒洋洋地连接,并且还提供断线/订阅处置时释放事件.

private IObservable<string> GetStrings()
{
    return Observable.Create<string>(o=>
    {
        SomeDataObject.ReadyEventHandler ReadyHandler = null;
        SomeDataObject.ErrorEventHandler ErrorHandler = null;

        ReadyHandler += () =>
        {
            for (int i =0; i < dataObject.ItemCount; i++)
                o.OnNext(dataObject[i].ToString());

            o.OnCompleted();
        }

        ErrorHandler += () =>
        {
            o.OnError(new Exception("oops!"));
        }

        dataObject.Ready += ReadyHandler;
        dataObject.Error += ErrorHandler;

        dataObject.DoRequest();

        return Disposable.Create(()=>
            {
                dataObject.Ready -= ReadyHandler;
                dataObject.Error -= ErrorHandler;
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

我也会考虑转移dataObject到该方法的参数.在异步系统中共享状态是问题的根源.