Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 编写可用和可维护的代码_.net_System.reactive_Reactive Programming - Fatal编程技术网

.net 编写可用和可维护的代码

.net 编写可用和可维护的代码,.net,system.reactive,reactive-programming,.net,System.reactive,Reactive Programming,我是反应式编程新手,遇到了一个问题 我的代码如下所示: IsBusy = true; service.BeginGetClients(param, c => { var r = service.EndGetClients(c); if(!CheckResult(r)) { service.BeginGetCachedClients(param, c2 =>

我是反应式编程新手,遇到了一个问题

我的代码如下所示:

    IsBusy = true;
    service.BeginGetClients(param, c => 
    {
        var r = service.EndGetClients(c);
        if(!CheckResult(r))
        {
            service.BeginGetCachedClients(param, c2 =>
                {
                    var r2 = service.EndGetCachedClients(c2);
                    if(CheckResult(r2))
                        ShowMessage("clients valid");
                    else
                        ShowMessage("clients not valid");

                    UpdateClients(r2);

                    service.BeginUpdateClients(r2, c3 =>
                        {
                            var b = service.EndUpdateClients(c3);
                            if(b)
                                ShowMessage("clients updated");
                            else
                                ShowMessage("clients not updated");
                            IsBusy = false;
                        }, null);

                }, null);
        }
        else
        {
            ShowMessage("error on get clients");
            IsBusy = false;
        }
    }, null);
如何更改为fluent Rx?我从以下代码开始:

    var invokeClients = Observable.FromAsyncPattern<Param, List<Client>>(service.BeginGetClients, service.EndGetClients);
    var invokeCachedClients = Observable.FromAsyncPattern<Param, List<Client>>(service.BeginGetCachedClients, service.EndGetCachedClients);
    invokeClients(param)
    .Subscribe(r =>
    {
        if(!CheckResult(r))
        {
            invokeCachedClients(param)
            .Subscribe(r2 =>
            {
                // TODO: next op
            });
        }
    });
var invokeClients=Observable.FromAsyncPattern(service.BeginGetClients,service.EndGetClients);
var invokeCachedClient=Observable.FromAsyncPattern(service.beginGetCachedClient,service.endGetCachedClient);
调用客户端(参数)
.订阅(r=>
{
如果(!检查结果(r))
{
InvokeCachedClient(参数)
.订阅(r2=>
{
//TODO:下一次行动
});
}
});
有什么改进代码的建议吗?也许还有别的解决办法? 我不喜欢这个级联代码

谢谢

invokeClients(param)
    .Where(x => !CheckResult(x))
    .Select(invokeCachedClients)
    .Do(_ => IsBusy = true)
    .Merge()
    .Do(_ => IsBusy = false)
    .Subscribe(x => Console.WriteLine("Do something here"));

确保订阅,否则它将不起作用(这就像不进行LINQ查询)

像这样的事情,你总是想彻底改变。转换这一点最困难的部分是异步调用之间的部分。如果您将一个右键的结果输入到下一个右键,那么它将是从async1中的x()到async2(x)中的y的直接
。我看到了两个功能,可以将其分解为:

public IObserservable<string> UpdateCachedClients(object param)
{
    var getCachedClientsAsync = Observable.FromAsyncPattern<...>(service.BeginGetCachedClients, service.EndGetCachedClients);
    var updateClientsAsync = Observable.FromAsyncPattern<...>(service.BeginUpdateClients, service.EndUpdateClients);

    return Observable.Create<string>(obs =>
    {
        return (from r2 in getCachedClientsAsync(param)
                            .Do(v => 
                                { if (CheckResult(v))
                                      obs.OnNext("clients valid");
                                  else
                                      obs.OnNext("clients not valid");
                                  //huh? is this done twice
                                  UpdateClients(v); 
                                })
                from b in updateClientsAsync(r2)
                select (b ? "clients updated" : "clients not updated")
               ).Subscribe(obs);
    });
}

public IObservable<string> UpdateAllClients(object param)
{
    var getClientsAsync = Observable.FromAsyncPattern<...>(service.BeginGetClients, service.EndGetClients);
    return from r in getClientsAsync(param)
           select (CheckResult(r) ? 
                     Observable.Return("error on get clients") :
                     UpdateCachedClients(param));
}
请注意,我在OnError和OnCompleted中都将
IsBusy
设置为false,因为这两个选项都是IObservable的终止消息


TPL似乎更适合这样的异步方法,因为它们只产生一个值,但在使用async/await的下一版本语言之前,如果您使用Tasks而不是IObservable,您可能会得到与您的方法或我的方法类似的语法。

如上所述

invokeClients(param)
  .Where(x => !CheckResult(x))
  .SelectMany(invokeCachedClients)
  .Subscribe(x => Console.WriteLine("Do something here"));
也可以写成

var query = from client in invokeClients(param)
  where !CheckResult(client)
  from cache in invokeCachedClients(client)
  select cache;
然后,您可以将busy标志包装在资源中

Func<IDisposable> busyResource = 
  () =>
  {
    IsBusy = true;
    return Disposable.Create(() => IsBusy = false);
  };
您倾向于使用方法而不是将IsBusy setters置于OnError或OnCompleted中的原因是,如果订阅也被释放,这将停止它


我相信我们可能会做得更好,但我发现很难理解你到底在做什么。老实说,我认为这实际上比Rx更适合TPL或数据工作流,也就是说,您实际上是在链接工作连续性,而不是对一系列事件作出反应。

谢谢,这对我帮助很大。但是如何中止第一次操作呢?不应调用“updateClientsAsync(r2)中的from b”。您将来更喜欢什么:异步/等待方法还是Rx?我也会添加IsBusy。
Func<IDisposable> busyResource = 
  () =>
  {
    IsBusy = true;
    return Disposable.Create(() => IsBusy = false);
  };
Observable.Using(busyResource, _=>query)
  .Subscribe(x=>Console.Write("Do something here");